linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/10] MA USB drivers cover letter
       [not found] <MA USB drivers>
@ 2014-11-03 20:42 ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (10 more replies)
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
  1 sibling, 11 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel


Media Agnostic (MA) USB enables the USB protocol to be used over a wide
range of physical media. MA USB is a relatively new protocol and is
currently unsupported in the Linux kernel. This patch set adds the
following drivers with the following capabilities:

1) MA USB Host:
        - provides functionality of a USB Host Controller.
        - implements MA USB protocol for a MA USB host.
        - provides MA USB packet transport over TCP

2) MA USB Device:
        - provides functionality of a USB Device Controller.
        - implements MA USB protocol for a MA USB device.
        - provides MA USB packet transport over TCP


Driver overview:

The MA USB Host and Device stacks each consists of two drivers. The first
driver is the Media Agnostic (MA) layer, which interfaces with the existing
USB stack and implements the MA USB protocol as defined in the MA USB
Specification Release 1.0. The second driver is the Media Specific (MS) layer.
The MS layer interfaces with the network stack to send and receive MA USB
packets via TCP.

When an MA USB driver is loaded, the MA layer loads first and registers
itself as a USB host controller with the USB Core. The MS layer then loads
and registers itself with the MA layer. Once the MS layer is registered,
the MA layer initiates creation of a communication channel for managment/control
packets. In the case of the MA USB host, the driver the opens a TCP socket
and polls periodically for a device. In the case of the MA USB device, the
driver identifies the MA USB host by IP address, then looks for and binds to
the open TCP socket of the MA USB host. When a connection event is initiated,
the MA USB host notifies the USB core and normal USB enumeration and
configuration results with each respective USB packet translated into its
MA USB equivalent.

Tools:

1) various scripts are included to help load and unload the MA USB host and
   device drivers.

2) a utility is included to help connect, disconnect, and test the MA USB 
   host and device drivers.

References:

MA USB Specification v1.0 available at www.usb.org/developers/docs/devclass_docs/


Stephanie Wallick (10):
  added media agnostic (MA) USB HCD driver
  added media agnostic (MA) USB HCD roothubs
  added media agnostic (MA) data structures and handling
  added media agnostic (MA) USB packet handling
  added media specific (MS) TCP drivers
  added media agnostic (MA) UDC
  added media agnostic (MA) USB management packet handling
  added media agnostic (MA) USB data packet handling
  added tools for building/loading media agnostic (MA) USB drivers
  added kernel build, configuration, and TODO files

 drivers/staging/Kconfig                            |    2 +
 drivers/staging/Makefile                           |    1 +
 drivers/staging/mausb/Kconfig                      |   16 +
 drivers/staging/mausb/Makefile                     |    3 +
 drivers/staging/mausb/TODO                         |   14 +
 drivers/staging/mausb/drivers/Kconfig              |   34 +
 drivers/staging/mausb/drivers/Makefile             |   20 +
 drivers/staging/mausb/drivers/mausb_const.h        |  109 ++
 drivers/staging/mausb/drivers/mausb_hcd.c          |  970 +++++++++++++
 drivers/staging/mausb/drivers/mausb_hcd.h          |  171 +++
 drivers/staging/mausb/drivers/mausb_hub.c          |  851 +++++++++++
 drivers/staging/mausb/drivers/mausb_hub.h          |  128 ++
 drivers/staging/mausb/drivers/mausb_ioctl.c        |  373 +++++
 drivers/staging/mausb/drivers/mausb_ioctl.h        |   99 ++
 drivers/staging/mausb/drivers/mausb_mem-host.c     |  404 ++++++
 drivers/staging/mausb/drivers/mausb_mem-host.h     |   74 +
 drivers/staging/mausb/drivers/mausb_mem.c          |  844 +++++++++++
 drivers/staging/mausb/drivers/mausb_mem.h          |  509 +++++++
 drivers/staging/mausb/drivers/mausb_mgmt.c         |  888 ++++++++++++
 drivers/staging/mausb/drivers/mausb_mgmt.h         |   90 ++
 drivers/staging/mausb/drivers/mausb_msapi.c        |  110 ++
 drivers/staging/mausb/drivers/mausb_msapi.h        |  232 +++
 drivers/staging/mausb/drivers/mausb_pkt.c          | 1038 ++++++++++++++
 drivers/staging/mausb/drivers/mausb_pkt.h          |  914 ++++++++++++
 drivers/staging/mausb/drivers/mausb_state.h        |  184 +++
 drivers/staging/mausb/drivers/mausb_tcp-device.c   |  147 ++
 drivers/staging/mausb/drivers/mausb_tcp-host.c     |  144 ++
 drivers/staging/mausb/drivers/mausb_tcp.c          |  446 ++++++
 drivers/staging/mausb/drivers/mausb_tcp.h          |  129 ++
 drivers/staging/mausb/drivers/mausb_tx-device.c    |  847 +++++++++++
 drivers/staging/mausb/drivers/mausb_tx-host.c      | 1211 ++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tx.c           |  318 +++++
 drivers/staging/mausb/drivers/mausb_tx.h           |  129 ++
 drivers/staging/mausb/drivers/mausb_udc.c          | 1488 ++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_udc.h          |  147 ++
 .../staging/mausb/scripts/build_load_connect.sh    |   69 +
 drivers/staging/mausb/scripts/load_gzero.sh        |    5 +
 drivers/staging/mausb/scripts/load_script.sh       |  125 ++
 drivers/staging/mausb/scripts/modprobify.sh        |   10 +
 drivers/staging/mausb/scripts/unload_all.sh        |   15 +
 drivers/staging/mausb/scripts/unload_gzero.sh      |    5 +
 drivers/staging/mausb/tools/mausb-util/Makefile    |   14 +
 drivers/staging/mausb/tools/mausb-util/README      |   30 +
 drivers/staging/mausb/tools/mausb-util/config.mk   |   17 +
 .../staging/mausb/tools/mausb-util/src/Android.mk  |   13 +
 .../staging/mausb/tools/mausb-util/src/Makefile    |   18 +
 .../staging/mausb/tools/mausb-util/src/connect.c   |   72 +
 .../staging/mausb/tools/mausb-util/src/connect.h   |   22 +
 drivers/staging/mausb/tools/mausb-util/src/mausb.c |  200 +++
 drivers/staging/mausb/tools/mausb-util/src/mausb.h |   64 +
 .../mausb/tools/mausb-util/src/mausb_ioctl.h       |   37 +
 drivers/staging/mausb/tools/mausb-util/src/utils.c |   94 ++
 52 files changed, 13894 insertions(+)
 create mode 100644 drivers/staging/mausb/Kconfig
 create mode 100644 drivers/staging/mausb/Makefile
 create mode 100644 drivers/staging/mausb/TODO
 create mode 100644 drivers/staging/mausb/drivers/Kconfig
 create mode 100644 drivers/staging/mausb/drivers/Makefile
 create mode 100755 drivers/staging/mausb/drivers/mausb_const.h
 create mode 100755 drivers/staging/mausb/drivers/mausb_hcd.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hcd.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.h
 create mode 100755 drivers/staging/mausb/drivers/mausb_mgmt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mgmt.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_state.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.h
 create mode 100644 drivers/staging/mausb/scripts/build_load_connect.sh
 create mode 100644 drivers/staging/mausb/scripts/load_gzero.sh
 create mode 100644 drivers/staging/mausb/scripts/load_script.sh
 create mode 100644 drivers/staging/mausb/scripts/modprobify.sh
 create mode 100644 drivers/staging/mausb/scripts/unload_all.sh
 create mode 100644 drivers/staging/mausb/scripts/unload_gzero.sh
 create mode 100644 drivers/staging/mausb/tools/mausb-util/Makefile
 create mode 100644 drivers/staging/mausb/tools/mausb-util/README
 create mode 100644 drivers/staging/mausb/tools/mausb-util/config.mk
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/Android.mk
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/Makefile
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/connect.c
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/connect.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb.c
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/utils.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 21:18     ` Greg KH
  2014-11-03 21:21     ` Greg KH
  2014-11-03 20:42   ` [PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
                     ` (9 subsequent siblings)
  10 siblings, 2 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we interface with the existing USB stack and implement the
functionality of a USB host controller driver. From the host's perspective,
we appear as just another USB host controller. However, instead of passing
traffic along a wired USB bus, the driver hands USB packets off for transport
per Media Agnostic USB protocol.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_hcd.c | 970 ++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_hcd.h | 171 ++++++
 2 files changed, 1141 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_hcd.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hcd.h

diff --git a/drivers/staging/mausb/drivers/mausb_hcd.c b/drivers/staging/mausb/drivers/mausb_hcd.c
new file mode 100755
index 0000000..03e8f0f
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hcd.c
@@ -0,0 +1,970 @@
+/* Name:	mausb_hcd.c
+ * Description: Creates and initializes a virtual USB host controller driver
+ *	        for the Media Agnostic USB host driver.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/gadget.h>
+#include <linux/kthread.h>
+#include <linux/random.h>
+
+#include "mausb_hcd.h"
+#include "mausb_hub.h"
+#include "mausb_pkt.h"
+#include "mausb_mem-host.h"
+#include "mausb_msapi.h"
+#include "mausb_mgmt.h"
+#include "mausb_state.h"
+#include "mausb_tx.h"
+
+static struct platform_device mausb_pdev;
+
+struct api_context {
+	struct completion	done;
+	int			status;
+};
+
+/*
+ * pointer conversion functions
+ */
+inline struct mausb_hcd *usb_hcd_to_mausb_hcd(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd))
+		return *((struct mausb_hcd **) (hcd->hcd_priv));
+	else
+		return *((struct mausb_hcd **) (hcd->primary_hcd->hcd_priv));
+}
+
+inline struct usb_hcd *mausb_hcd_to_usb_hcd(struct mausb_hcd *mhcd)
+{
+	if (mhcd->shared_hcd && !usb_hcd_is_primary_hcd(mhcd->shared_hcd))
+		return mhcd->shared_hcd;
+	else
+		return mhcd->usb_hcd;
+}
+
+inline struct device *mausb_hcd_to_dev(struct mausb_hcd *mhcd)
+{
+	return mausb_hcd_to_usb_hcd(mhcd)->self.controller;
+}
+
+inline struct mausb_urb *usb_urb_to_mausb_urb(struct urb *urb)
+{
+	return (struct mausb_urb *) urb->hcpriv;
+}
+/* ----------------------------------------------------------------- */
+
+/**
+ * @maurb:	Media agnostic structure with URB to release.
+ * @status:	Status for URB that is getting released.
+ *
+ * Removes an URB from the queue, deletes the media agnostic information in
+ * the urb, and gives the URB back to the HCD. Caller must be holding the
+ * driver's spinlock.
+ */
+void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status)
+{
+	struct urb		*urb;
+	struct usb_hcd		*hcd;
+	struct api_context	*ctx = NULL;
+	struct mausb_hcd	*mhcd = platform_get_drvdata(&mausb_pdev);
+	unsigned long		irq_flags;
+
+	if (!mhcd) {
+		printk(KERN_ERR "%s: No MA USB HCD\n", __func__);
+		return;
+	}
+
+	hcd = mausb_hcd_to_usb_hcd(mhcd);
+
+	spin_lock_irqsave(&mhcd->giveback_lock, irq_flags);
+
+	if (!maurb) {
+		mausb_err(mhcd, "%s: no maurb\n", __func__);
+		spin_unlock_irqrestore(&mhcd->giveback_lock, irq_flags);
+		return;
+	} else {
+		urb = maurb->urb;
+		ctx = urb->context;
+	}
+
+	if (!urb) {
+		mausb_err(mhcd, "%s: no urb\n", __func__);
+		mausb_internal_drop_maurb(maurb, mhcd);
+		spin_unlock_irqrestore(&mhcd->giveback_lock, irq_flags);
+		return;
+	}
+
+	mausb_dbg(mhcd, "%s: returning urb with status %i\n", __func__, status);
+
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
+
+	/* remove the mausb-specific data */
+	mausb_internal_drop_maurb(maurb, mhcd);
+
+	spin_unlock_irqrestore(&mhcd->giveback_lock, irq_flags);
+}
+
+/**
+ * Adds an URB to the endpoint queue then calls the URB handler. URB is wrapped
+ * in media agnostic structure before being enqueued.
+ */
+static int mausb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t memflags)
+{
+	int			ret = 0;
+	struct mausb_urb	*maurb;
+	struct mausb_hcd	*mhcd;
+	struct mausb_host_ep	*ep;
+	unsigned long		irq_flags;
+
+	if (!hcd || !urb) {
+		printk(KERN_ERR "%s: no %s\n", __func__,
+			(hcd ? "urb" : "USB hcd"));
+	}
+
+	mhcd = usb_hcd_to_mausb_hcd(hcd);
+	ep   = usb_to_ma_endpoint(urb->ep);
+
+	if (!ep || !mhcd) {
+		mausb_err(mhcd, "%s: no %s\n", __func__,
+			(ep ? "MA USB HCD" : "endpoint"));
+		return -EINVAL;
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		mausb_err(mhcd, "%s: urb already unlinked, status is %i\n",
+			__func__, urb->status);
+		return urb->status;
+	}
+
+	/* If the endpoint isn't activated, we can't enqueue anything. */
+	if (MAUSB_EP_HANDLE_UNASSIGNED == ep->ep_handle_state) {
+		mausb_err(mhcd, "%s: endpoint handle unassigned\n", __func__);
+		return -EPIPE;
+	}
+
+	if (USB_SPEED_FULL != urb->dev->speed) /* suppress checks */
+		ep->max_pkt = usb_endpoint_maxp(&urb->ep->desc);
+
+	/* initialize the maurb */
+	maurb = mausb_alloc_maurb(ep, memflags);
+	if (!maurb) {
+		mausb_err(mhcd, "could not allocate memory for MA USB urb\n");
+		return -ENOMEM;
+	}
+
+	/* set maurb member values */
+	maurb->urb = urb;
+	urb->hcpriv = maurb;
+
+	/* submit urb to hcd and add to endpoint queue */
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret < 0) {
+		mausb_err(mhcd, "urb enqueue failed: error %d\n", ret);
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+		return ret;
+	}
+
+	/* get usb device and increment reference counter */
+	if (!mhcd->udev) {
+		mhcd->udev = urb->dev;
+		usb_get_dev(mhcd->udev);
+	}
+
+	/* add urb to queue list */
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	list_add_tail(&maurb->urb_list, &ep->urb_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	/* add urb to ma hcd urb list */
+	spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+	list_add_tail(&maurb->ma_hcd_urb_list, &mhcd->enqueue_urb_list);
+	spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+	/* send to MA transfer process */
+	wake_up(&mhcd->waitq);
+
+	return ret;
+}
+
+/**
+ * Dequeues an URB.
+ */
+static int mausb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	int			ret	= 0;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_host_ep	*ep = usb_to_ma_endpoint(urb->ep);
+	struct mausb_urb	*maurb = usb_urb_to_mausb_urb(urb);
+	unsigned long		irq_flags;
+
+	/* For debugging - we want to know who initiated URB dequeue. */
+	dump_stack();
+
+	if (ep->active_transfer == maurb) {
+		ret = mausb_tx_dev_mgmt_req_ep(CancelTransferReq,
+			&mhcd->ma_dev.mgmt, maurb->dev, true, ep);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		ep->active_transfer = NULL;
+		ep->state.tx_pending = 0;
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	}
+
+	/*
+	 * Make sure urb hasn't been unlinked or already completed.
+	 * Dequeue must fail if usb_hcd_check_unlink_urb() fails.
+	 */
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+
+	if (ret < 0) {
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		mausb_err(mhcd, "%s: urb already unlinked or completed, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* check to make sure our urb queue is not empty */
+	if (list_empty(&ep->urb_list)) {
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		mausb_err(mhcd, "%s: urb queue is empty\n", __func__);
+		return -ENXIO;
+	}
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	/* now we can give back URB */
+	spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	mausb_unlink_giveback_urb(maurb, -EINPROGRESS);
+	spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+	return ret;
+}
+
+/**
+ * Called by usb core to suspend the bus. Once suspended, hcd waits in
+ * that state until it is resumed by mausb_bus_resume().
+ *
+ * Note: sections are commented out to accomidate devices that don't yet
+ * support SleepReq packets.
+ *
+ * Always returns zero.
+ */
+static int mausb_bus_suspend(struct usb_hcd *hcd)
+{
+/*	int			ret = 0; */
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+/*	struct mausb_dev	*top_dev = mhcd->ma_dev.top_dev; */
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+/*	if (NULL != top_dev) {
+		ret = mausb_tx_dev_mgmt_req(SleepReq,
+			&mhcd->ma_dev.mgmt, top_dev, true);
+		if (ret < 0)
+			return ret;
+	}
+*/
+	/* stop polling */
+	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+	/*
+	 * Avoid suspend/resume race condition by making sure there aren't any
+	 * devices in the middle of resuming. If a connected device is
+	 * resuming, suspend should fail.
+	 */
+	if (mhcd->resuming) {
+		mausb_err(mhcd, "%s: suspend failed, device is resuming\n",
+			 __func__);
+		return -EBUSY;
+	}
+
+	mausb_dbg(mhcd, "%s: suspending mausb driver\n", __func__);
+
+	roothub->rh_state = MAUSB_RH_SUSPEND;
+	hcd->state = HC_STATE_SUSPENDED;
+
+	return 0;
+}
+
+/**
+ * Called by usb core to resume hcd after bus suspension.
+ *
+ * Returns 0 if resume was successful, otherwise returns negative error
+ * value.
+ */
+static int mausb_bus_resume(struct usb_hcd *hcd)
+{
+	int ret = 0;
+	struct mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_dev *top_dev = mhcd->ma_dev.top_dev;
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		mausb_err(mhcd, "%s: hcd not fully powered\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	mausb_dbg(mhcd, "%s: resuming mausb driver\n", __func__);
+
+	hcd->state = HC_STATE_RUNNING;
+	roothub->rh_state = MAUSB_RH_RUNNING;
+
+	if (NULL != top_dev) {
+		ret = mausb_tx_dev_mgmt_req(WakeReq, &mhcd->ma_dev.mgmt,
+			top_dev, true);
+
+		if (ret < 0) {
+			mausb_err(mhcd, "%s: WakeReq was unsuccessful"
+				" (error %i)\n", __func__, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Returns the hardware-chosen device address.
+ */
+static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	int			ret = 0;
+	struct ma_dev		*ma_dev;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_host_ep	*ma_ep;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (NULL == mhcd)
+		return -EINVAL;
+
+	ma_dev = &mhcd->ma_dev;
+	if (NULL == ma_dev)
+		return -EINVAL;
+
+	mausb_dev = mausb_find_dev_host(ma_dev, udev);
+	if (NULL == mausb_dev)
+		return -ENODEV;
+
+	ret = mausb_tx_dev_mgmt_req(USBDevHandleReq, &ma_dev->mgmt,
+		mausb_dev, true);
+
+	if (-ETIMEDOUT == ret) {
+		mausb_err(mhcd, "USBDevHandleReq timed out\n");
+	} else if (0 > ret) {
+		mausb_err(mhcd, "USBDevHandleReq failed with error %i\n", ret);
+	} else {
+		ret = mausb_tx_dev_mgmt_req(EPHandleReq, &ma_dev->mgmt,
+			mausb_dev, true);
+
+		if (-ETIMEDOUT == ret) {
+			mausb_err(mhcd, "EPHandleReq timed out\n");
+		} else if (0 > ret) {
+			mausb_err(mhcd, "EPHandleReq failed with error %i\n",
+					ret);
+		} else {
+			ret = mausb_tx_dev_mgmt_req(SetUSBDevAddrReq,
+				&ma_dev->mgmt, mausb_dev, true);
+
+			if (-ETIMEDOUT == ret) {
+				mausb_err(mhcd, "SetUSBDevAddrReq timed out\n");
+			} else if (0 > ret) {
+				mausb_err(mhcd, "SetUSBDevAddrReq failed with"
+					" error %i\n", ret);
+			} else {
+				ma_ep = mausb_find_ep_host(&udev->ep0,
+					mausb_dev);
+				ret = mausb_tx_dev_mgmt_req_ep(ModifyEP0Req,
+					&ma_dev->mgmt, mausb_dev, true, ma_ep);
+			}
+		}
+	}
+
+	/* TODO: handle failed enumeration */
+
+	return 0;
+}
+
+/**
+ * Resets everything to default values. Always returns zero.
+ */
+static int mausb_reset(struct usb_hcd *hcd)
+{
+	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	mausb_dbg(mhcd, "%s: resetting MA USB host driver . . .\n", __func__);
+
+	roothub->rh_state = MAUSB_RH_RESETTING;
+
+	if (mausb_is_ss_hcd(hcd)) {
+		hcd->speed = HCD_USB3;
+		hcd->self.root_hub->speed = USB_SPEED_SUPER;
+	} else {
+		hcd->speed = HCD_USB2;
+		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+		hcd->has_tt = 1;
+	}
+
+	hcd->uses_new_polling = 1;
+	hcd->self.sg_tablesize = 0;
+
+	mausb_init_port_status(&mhcd->root_hub);
+	mausb_init_port_status(&mhcd->shared_root_hub);
+
+	return 0;
+}
+
+int mausb_hcd_thread(void *data)
+{
+	struct mausb_hcd *mhcd = (struct mausb_hcd *)data;
+	struct mausb_urb *ma_urb, *next_ma_urb;
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	while (!kthread_should_stop()) {
+		spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+		list_for_each_entry_safe(ma_urb, next_ma_urb,
+			&mhcd->enqueue_urb_list, ma_hcd_urb_list) {
+
+			list_move(&ma_urb->ma_hcd_urb_list,
+				&mhcd->transfer_urb_list);
+
+			spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+			ma_ep = ma_urb->ep;
+			start_ma_transfer(ma_ep, ma_urb,
+				usb_pipein(ma_urb->urb->pipe));
+
+			spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+		}
+		spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+		wait_event_interruptible(mhcd->waitq,
+			!list_empty(&mhcd->enqueue_urb_list) ||
+			kthread_should_stop());
+	}
+
+	do_exit(0);
+	return 0;
+}
+
+/**
+ * Tells the hcd to start running. Always returns zero.
+ */
+static int mausb_start(struct usb_hcd *hcd)
+{
+	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	mausb_dbg(mhcd, "%s: starting MA USB driver . . .\n", __func__);
+
+	hcd->state = HC_STATE_RUNNING;
+	roothub->rh_state = MAUSB_RH_RUNNING;
+
+	spin_lock_init(&mhcd->hcd_lock);
+	INIT_LIST_HEAD(&mhcd->ma_dev.dev_list);
+	INIT_LIST_HEAD(&mhcd->enqueue_urb_list);
+	spin_lock_init(&mhcd->urb_list_lock);
+	INIT_LIST_HEAD(&mhcd->transfer_urb_list);
+	spin_lock_init(&mhcd->giveback_lock);
+	init_waitqueue_head(&mhcd->waitq);
+	mhcd->ma_hcd_task_data = (void *)mhcd;
+	mhcd->ma_hcd_task = kthread_run(mausb_hcd_thread,
+		mhcd->ma_hcd_task_data, "mausb_hcd_thread");
+
+	return 0;
+}
+
+/**
+ * Called when driver is removed (specifically during usb_remove_hcd). This is
+ * where we tell the hcd to stop writing memory and doing I/O.
+ */
+static void mausb_stop(struct usb_hcd *hcd)
+{
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (mhcd->ma_hcd_task != NULL) {
+		kthread_stop(mhcd->ma_hcd_task);
+		mhcd->ma_hcd_task = NULL;
+	}
+
+	mausb_dbg(mhcd, "%s: stopping mausb driver . . .\n", __func__);
+}
+
+static const struct hc_driver mausb_hc_driver = {
+	.description = "mausb-hcd",
+	.product_desc = "mausb pseudo-host controller",
+	.hcd_priv_size = sizeof(struct mausb_hcd),
+	.irq = NULL,
+	.flags = HCD_USB3,
+	.reset = &mausb_reset,
+	.start = &mausb_start,
+	.stop = &mausb_stop,
+	.urb_enqueue = &mausb_urb_enqueue,
+	.urb_dequeue = &mausb_urb_dequeue,
+	.hub_status_data = &mausb_hub_status_data,
+	.hub_control = &mausb_hub_control,
+	.bus_suspend = &mausb_bus_suspend,
+	.bus_resume = &mausb_bus_resume,
+	.alloc_dev = &mausb_alloc_dev,
+	.free_dev =  &mausb_free_dev,
+	.add_endpoint =    &mausb_add_endpoint,
+	.drop_endpoint =   &mausb_drop_endpoint,
+	.check_bandwidth = &mausb_check_bandwidth,
+	.reset_bandwidth = &mausb_reset_bandwidth,
+	.address_device =  &mausb_address_device,
+};
+
+/**
+ * Sets the host_bos fields to the proper initial values per USB3 spec,
+ * section 10.13.1.
+ */
+static int mausb_set_host_bos(struct mausb_host_bos *host_bos)
+{
+	/* BOS Descriptor */
+	host_bos->bos_des.bLength         = USB_DT_BOS_SIZE;
+	host_bos->bos_des.bDescriptorType = USB_DT_BOS;
+	host_bos->bos_des.wTotalLength    = sizeof(struct mausb_host_bos);
+	host_bos->bos_des.bNumDeviceCaps  = MAUSB_HOST_NUM_DEV_CAPS;
+
+	/* SuperSpeed USB Device Capability */
+	host_bos->ss_cap_des.bLength               = USB_DT_USB_SS_CAP_SIZE;
+	host_bos->ss_cap_des.bDescriptorType       = USB_DT_DEVICE_CAPABILITY;
+	host_bos->ss_cap_des.bDevCapabilityType    = USB_SS_CAP_TYPE;
+	host_bos->ss_cap_des.bmAttributes          = USB_LTM_SUPPORT;
+	host_bos->ss_cap_des.wSpeedSupported       = USB_5GBPS_OPERATION;
+	host_bos->ss_cap_des.bFunctionalitySupport = MAUSB_SUPER_SPEED;
+	host_bos->ss_cap_des.bU1devExitLat         = MAUSB_HOST_U1_DEV_EXIT_LAT;
+	host_bos->ss_cap_des.bU2DevExitLat         = MAUSB_HOST_U2_DEV_EXIT_LAT;
+
+	return 0;
+}
+
+/**
+ * @req:	The incoming MA USB management request packet to handle.
+ * @resp:	The MA USB management response packet to send out.
+ * @mgmt:	The MA USB HCD's management structure.
+ *
+ * This function handles management requests to the HCD. It parses the packet
+ * and makes the necessary function calls into the system.
+ *
+ * Note: this function only completes the packet type, status and
+ * request-specific data-fields. the remainder of the fields are set
+ * by mausb_rx_mgmt_req
+ */
+static int hcd_mgmt_req_switch(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt)
+{
+	int ret = 0;
+
+	switch (req->common.pkt_type) {
+
+	/* TODO: handle unimplemented request types */
+	case RemoteWakeReq:
+	case DevInitDisconnectReq:
+		break;
+	case PingReq:
+		resp->common.pkt_type   = PingResp;
+		resp->common.pkt_status = NO_ERROR;
+		break;
+	/* invalid packet type */
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int mausb_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context);
+
+/**
+ * Generates the mass_id used to initialize an MA USB device. Uses a random
+ * number generator to choose a random id between 1 and 254.
+ *
+ * Returns the random id chosen.
+ */
+static __u8 get_mass_id(void)
+{
+       __u8 id;
+
+       get_random_bytes(&id, sizeof(id));
+
+       /* Note: this function is twice as likely to pick 1 or 2 */
+       id = (id % (MASS_ID_MAX - MASS_ID_MIN + 1) + MASS_ID_MIN);
+
+       return id;
+}
+
+/**
+ * Initializes MA USB hcd roothub descriptors and ports.
+ *
+ * Always returns zero.
+ */
+static int create_mausb_hcd(struct mausb_hcd *mausb_hcd)
+{
+	if (mausb_hcd == NULL)
+		return -ENOMEM;
+
+	/* set the roothub descriptor to the proper initial values */
+	mausb_set_hub_descriptor(&mausb_hcd->root_hub.descriptor);
+	mausb_set_ss_hub_descriptor(&mausb_hcd->shared_root_hub.descriptor);
+
+	/* set the host_bos to the proper values */
+	mausb_set_host_bos(&mausb_hcd->host_bos);
+
+	/* initialize port status values */
+	mausb_init_port_status(&mausb_hcd->root_hub);
+	mausb_init_ss_port_status(&mausb_hcd->shared_root_hub);
+
+	/* initialize the MA USB device structure */
+	mausb_init_ma_device(&mausb_hcd->ma_dev, MAUSB_DEV_ADDR, get_mass_id(),
+		mausb_hcd, NULL, &hcd_mgmt_req_switch, &mausb_device_connect);
+
+	return 0;
+}
+
+/**
+ * probe function
+ */
+static int mausb_probe(struct platform_device *mausb_pdev)
+{
+	int			ret = 0;
+	const char		*bus_name = "MAUSB";
+	unsigned int		mausb_irqnum = 0;
+	struct usb_hcd		*usb_hcd;
+	struct mausb_hcd	*mhcd;
+
+	/* create our USB 2.0 roothub */
+	usb_hcd = usb_create_hcd(&mausb_hc_driver, &mausb_pdev->dev, bus_name);
+	if (usb_hcd == NULL) {
+		dev_err(&mausb_pdev->dev, "%s: could not create USB HCD\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* create our data structure that holds MA USB data */
+	mhcd = kzalloc(sizeof(struct mausb_hcd), GFP_KERNEL);
+	ret = create_mausb_hcd(mhcd);
+	if (ret < 0) {
+		dev_err(&mausb_pdev->dev, "%s: could not create MA USB HCD"
+			" (error %i)\n", __func__, ret);
+
+		if (ret != -ENOMEM)
+			kfree(mhcd);
+
+		return ret;
+	}
+
+	/*
+	 * Everyone exchanges pointers so we can move between data types with
+	 * minimal pointer juju.
+	 */
+	platform_set_drvdata(mausb_pdev, mhcd);
+	*((struct mausb_hcd **) usb_hcd->hcd_priv) = mhcd;
+	mhcd->usb_hcd = usb_hcd;
+
+	/*
+	 * Finish initializing generic members of USB 2.0 HCD, register the bus,
+	 * request IRQ line, call driver's reset() and start() routines.
+	 */
+	ret = usb_add_hcd(usb_hcd, mausb_irqnum, IRQF_SHARED);
+	if (ret) {
+		dev_err(&mausb_pdev->dev, "%s: could not add USB HCD"
+			" (error %i)\n", __func__, ret);
+
+		usb_remove_hcd(usb_hcd);
+		kfree(mhcd);
+
+		return ret;
+	}
+
+	/* add our USB 3.0 roothub */
+	mhcd->shared_hcd = usb_create_shared_hcd(&mausb_hc_driver,
+		&mausb_pdev->dev, bus_name, usb_hcd);
+
+	if (mhcd->shared_hcd == NULL) {
+		dev_dbg(&mausb_pdev->dev,
+			"%s: could not create shared USB HCD\n", __func__);
+
+		usb_remove_hcd(usb_hcd);
+		kfree(mhcd);
+
+		return -ENOMEM;
+	}
+
+	ret = usb_add_hcd(mhcd->shared_hcd, mausb_irqnum, IRQF_SHARED);
+
+	if (ret) {
+		dev_err(&mausb_pdev->dev, "%s: could not add shared"
+			" USB HCD (error %i)\n", __func__, ret);
+
+		usb_remove_hcd(usb_hcd);
+		kfree(mhcd);
+	}
+
+	return ret;
+}
+
+/**
+ * remove function
+ */
+static int mausb_remove(struct platform_device *mausb_pdev)
+{
+	int			ret = 0;
+	struct usb_hcd		*hcd, *shared_hcd;
+	struct mausb_hcd	*mhcd = platform_get_drvdata(mausb_pdev);
+
+	if (mhcd == NULL) {
+		dev_err(&mausb_pdev->dev,
+			"%s:MA USB HCD not found\n", __func__);
+		return 0;
+	}
+
+	hcd = mhcd->usb_hcd;
+	shared_hcd = mhcd->shared_hcd;
+
+	if (mhcd->shared_hcd) {
+		usb_remove_hcd(mhcd->shared_hcd);
+		usb_put_hcd(mhcd->shared_hcd);
+		mhcd->shared_hcd = NULL;
+	}
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+
+	kfree(mhcd);
+
+	return ret;
+}
+
+/**
+ * Release function.
+ */
+static void mausb_dev_release(struct device *dev)
+{
+	/* TODO: if we dynamically allocate anything, free it here */
+}
+
+static struct platform_driver mausb_driver = {
+	.probe = mausb_probe,
+	.remove = mausb_remove,
+	.driver = {
+		.name = MAUSB_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_device mausb_pdev = {
+	.name = MAUSB_NAME,
+	.id = 0,
+};
+
+/**
+ * @pkt		The incoming MA USB packet to parse.
+ * @context	The MA USB HCD's management structure.
+ *
+ * Used to transfer MA USB management packets to and from an MA USB device.
+ */
+static int mausb_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context)
+{
+	int			ret;
+	struct mausb_mgmt	*mgmt;
+	struct mausb_hcd	*mhcd = platform_get_drvdata(&mausb_pdev);
+	struct mausb_pkt	*pkt = mausb_pkt_from_ms_pkt_ma_dev(ms_pkt,
+					&mhcd->ma_dev, GFP_ATOMIC);
+
+	if ((NULL == context) || (NULL == pkt)) {
+		mausb_err(mhcd, "%s: received NULL input\n", __func__);
+		return -EFAULT;
+	}
+
+	mgmt = (struct mausb_mgmt *) context;
+
+	ret = mausb_rx_mgmt(pkt, mgmt);
+
+	return ret;
+}
+
+/**
+ * @drv:	The media specific driver structure that provides an interface
+ *		for the media agnostic driver.
+ *
+ * Registers a media specific driver with the MA USB HCD.
+ */
+struct mausb_ma_drv *mausb_register_ms_driver(struct mausb_ms_drv *drv)
+{
+	struct mausb_hcd	*mhcd = platform_get_drvdata(&mausb_pdev);
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	mhcd->ma_dev.ms_driver = drv;
+	spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+	/* Open the management channel */
+	mausb_add_mgmt_channel(&mhcd->ma_dev.mgmt, drv,
+			 &mausb_transfer_mgmt_packet, &mausb_mgmt_pkt_sent);
+
+	return &mhcd->ma_dev.ma_drv;
+}
+EXPORT_SYMBOL(mausb_register_ms_driver);
+
+/**
+ * Called by a media specific driver to indicate that an MA USB device has been
+ * connected and is ready to receive MA USB packets.
+ */
+int mausb_device_connect(int on)
+{
+	int status = 0;
+	/* TODO: don't want portnum hard coded when we add more ports */
+	int portnum = 0;
+	struct mausb_hcd	*mhcd = platform_get_drvdata(&mausb_pdev);
+
+	/*  connection event */
+	if (on) {
+		/* reset MA USB device */
+		status = mausb_tx_dev_mgmt_req(DevResetReq, &mhcd->ma_dev.mgmt,
+			NULL, true);
+
+		if (status < 0) {
+			mausb_err(mhcd, "%s: cannot reset MA device,"
+				" error %i\n", __func__, status);
+			return status;
+		}
+
+		/* send CapResp packet */
+		if (0 <= status) {
+			status = mausb_tx_dev_mgmt_req(CapReq,
+				&mhcd->ma_dev.mgmt, NULL, true);
+		}
+
+		if (status < 0) {
+			mausb_err(mhcd, "%s: cannot get device capabilities,"
+				" error %i\n", __func__, status);
+			return status;
+		}
+	}
+
+	status = mausb_connect(mhcd, portnum, on);
+
+	return status;
+}
+
+/**
+ * initialization function
+ */
+static int mausb_hcd_init(void)
+{
+	int ret;
+
+	/* register HCD driver */
+	ret = platform_driver_register(&mausb_driver);
+	if (ret < 0) {
+		printk(KERN_DEBUG "%s: failed to register HC driver: "
+			" error number %d\n", __func__, ret);
+
+	} else {
+		/* register HCD device */
+		ret = platform_device_register(&mausb_pdev);
+
+		if (ret < 0) {
+			printk(KERN_DEBUG "%s: failed to register HC device:"
+				"error number %d\n", __func__, ret);
+			platform_driver_unregister(&mausb_driver);
+		} else {
+			/* direct the release function (for exiting) */
+			mausb_pdev.dev.release = &mausb_dev_release;
+
+			if (ret < 0) {
+				printk(KERN_DEBUG "failed to register HC"
+					" chardev: error number %d\n", ret);
+				platform_driver_unregister(&mausb_driver);
+				platform_device_unregister(&mausb_pdev);
+			}
+		}
+	}
+
+	return ret;
+}
+module_init(mausb_hcd_init);
+
+/**
+ * Exit function.
+ */
+static void mausb_hcd_exit(void)
+{
+	/* deregister HC device */
+	platform_device_unregister(&mausb_pdev);
+
+	/* deregister HC driver */
+	platform_driver_unregister(&mausb_driver);
+}
+module_exit(mausb_hcd_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("MA USB driver");
diff --git a/drivers/staging/mausb/drivers/mausb_hcd.h b/drivers/staging/mausb/drivers/mausb_hcd.h
new file mode 100644
index 0000000..29c431a
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hcd.h
@@ -0,0 +1,171 @@
+/* Name:         mausb_hcd.h
+ * Description:  header file for mausb_hcd.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_HCD_H
+#define __MAUSB_HCD_H
+
+#include <linux/spinlock.h>
+
+#include "mausb_hub.h"
+#include "mausb_pkt.h"
+#include "mausb_mem.h"
+#include "mausb_const.h"
+
+#define MAUSB_NAME "mausb"
+
+#define mausb_info(mhcd, fmt, args...) \
+	dev_info(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_dbg(mhcd, fmt, args...) \
+	dev_dbg(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_warn(mhcd, fmt, args...) \
+	dev_warn(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_err(mhcd, fmt, args...) \
+	dev_err(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+
+/* Transfer directions */
+#define PIPE_DIR_OUT 0
+#define PIPE_DIR_IN 1
+
+/* Host BOS parameters */
+#define MAUSB_HOST_NUM_DEV_CAPS 1
+#define MAUSB_HOST_U1_DEV_EXIT_LAT 0
+#define MAUSB_HOST_U2_DEV_EXIT_LAT 0
+
+/* TEMPORARY: the mausb device will have this handle */
+#define MAUSB_DEV_ADDR 0x54
+#define MAUSB_MASS_ID  0x25
+
+struct mausb_ms_drv;
+
+/**
+ * This structure holds the information set in a get bos descriptor request.
+ *
+ * @bos_des:     Binary Object Store Descriptor, per USB2.0 Spec
+ * @ss_cap_des:  SuperSpeed Capability Descriptor, per USB3.0 Spec
+ */
+struct __attribute__((__packed__)) mausb_host_bos {
+	struct usb_bos_descriptor             bos_des;
+	struct usb_ss_cap_descriptor          ss_cap_des;
+};
+
+/**
+ * This structure holds all of the MA USB-specific data.
+ *
+ * All data listed in this structure is protected by the hcd_lock.
+ * if you want to use any of this data, you need to be in possession
+ * of this lock.
+ *
+ * @root_hub:		Contains all of the data for the USB 2.0 roothub.
+ *			This includes status, state and descriptors.
+ * @shared_root_hub:	Contains all of the data for the USB 3.0 roothub.
+ *			This includes status, state and descriptors
+ * @host_bos:		Stores the host's BOS descriptor
+ * @udev:		Pointer to the usb device we are currently sending
+ *			a packet to.
+ * @shared_hcd:		The second host controller structure for the MAUSB
+ *			driver. We need this because we do SuperSpeed, which
+ *			requires 2 root hubs.
+ * @ma_dev:		The connected MA USB device
+ * @ma_hcd_task:	Task for handling urb queue
+ * @ma_hcd_task_data:	Context for ma_hcd_task
+ * @waitq:		Event trigger for dequeue
+ * @enqueue_urb_list:	List of enqueued urbs from core
+ * @transfer_urb_list:	List of urbs awaiting ma transfer
+ * @urb_list_lock:	Lock for accessing urb lists
+ * @hcd_lock:		Lock for accessing data in this structure. note that
+ *			endpoints have their own locks. When accessing
+ *			endpoint data, this lock should NOT be held
+ * @giveback_lock:	spin lock to prevent preemption when give back an urb
+ * @resuming:		Set to 1 when HCD is resuming
+ * @disabled:		Set to 1 when hcd is disabled
+ */
+struct __attribute__((__packed__)) mausb_hcd  {
+	struct mausb_root_hub	root_hub;
+	struct mausb_root_hub	shared_root_hub;
+
+	struct mausb_host_bos	host_bos;
+
+	struct usb_device	*udev;
+
+	struct usb_hcd		*usb_hcd;
+	struct usb_hcd		*shared_hcd;
+
+	struct ma_dev		ma_dev;
+	struct task_struct	*ma_hcd_task;
+	void			*ma_hcd_task_data;
+	wait_queue_head_t	waitq;
+	struct list_head	enqueue_urb_list;
+	struct list_head	transfer_urb_list;
+	spinlock_t		urb_list_lock;
+	spinlock_t		hcd_lock;
+	spinlock_t		giveback_lock;
+	unsigned int		resuming:1;
+	unsigned int		disabled:1;
+};
+
+/* Pointer conversion functions */
+inline struct mausb_hcd *usb_hcd_to_mausb_hcd(struct usb_hcd *hcd);
+inline struct usb_hcd *mausb_hcd_to_usb_hcd(struct mausb_hcd *mhcd);
+inline struct device *mausb_hcd_to_dev(struct mausb_hcd *mhcd);
+inline struct mausb_urb *usb_urb_to_mausb_urb(struct urb *urb);
+
+/* URB handling functions */
+void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status);
+
+/* Connection event function */
+int mausb_device_connect(int);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 02/10] added media agnostic (MA) USB HCD roothubs
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we implement USB 2.0 and 3.0 roothubs. From the host's perspective,
hub state is set and tracked just like any other USB roothub. Likewise, requests
to the roothub appear to be handled like any other wired USB request.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_hub.c | 851 ++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_hub.h | 128 +++++
 2 files changed, 979 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.h

diff --git a/drivers/staging/mausb/drivers/mausb_hub.c b/drivers/staging/mausb/drivers/mausb_hub.c
new file mode 100644
index 0000000..aebca54
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hub.c
@@ -0,0 +1,851 @@
+/* Name:         mausb_hub.c
+ * Description:  mausb hub structures and functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/ch9.h>
+
+#include "mausb_hub.h"
+#include "mausb_hcd.h"
+
+/**
+ * Returns MA USB roothub data structure for a USB HCD.
+ */
+struct mausb_root_hub *usb_hcd_to_roothub(struct usb_hcd *hcd)
+{
+	struct mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (usb_hcd_is_primary_hcd(hcd))
+		return &mhcd->root_hub;
+	else
+		return &mhcd->shared_root_hub;
+}
+
+/**
+ * Returns true if the given is the superspeed HCD. Note: The primary HCD is
+ * High Speed and the shared HCD is SuperSpeed.
+ */
+bool mausb_is_ss_hcd(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd))
+		return false;
+	else
+		return true;
+}
+
+/**
+ * Sets downstream port link state.
+ *
+ * @mhcd:	MA USB hcd that owns port.
+ * @state:	Link state to be set (see USB 3.0 spec for link state values).
+ * @portnum:	Port number of link state to be set.
+ */
+void set_link_state(struct mausb_root_hub *roothub, int state, int portnum)
+{
+	struct usb_port_status   *port_stat;
+
+	port_stat = &roothub->port_status[portnum];
+
+		port_stat->wPortStatus &= LINK_STATE_MASK;
+		port_stat->wPortStatus |= state;
+}
+
+/**
+ * Generates connect or disconnect event for a roothub.
+ *
+ * @hcd:	HCD associated with roothub.
+ * @do_connect: 1 for connect, 0 for disconnect.
+ * @_portnum:	Port number of connected device.
+ * @is_SS:	True if roothub is SuperSpeed or higher, otherwise false.
+ */
+int port_connect(struct usb_hcd *hcd, int do_connect, int _portnum, bool is_SS)
+{
+	int			portnum = _portnum;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	if (portnum >= MAUSB_ROOTHUB_NUM_PORTS) {
+		mausb_err(mhcd, "%s: port number %i is too large (max = %i)\n",
+			__func__, portnum, MAUSB_ROOTHUB_NUM_PORTS);
+		return -EINVAL;
+	}
+
+	/* if new connection, assign first empty port */
+	if (do_connect > 0) {
+		portnum = 0;
+		while (roothub->port_status[portnum].wPortStatus
+			& USB_PORT_STAT_CONNECTION) {
+			portnum++;
+		}
+
+		mausb_dbg(mhcd, "%s: assigned MA USB port number %d\n",
+		__func__, portnum);
+	}
+
+	/*
+	 * If new connection, we assigned portnum above, otherwise use portnum
+	 * passed in.
+	 */
+	port_stat = &roothub->port_status[portnum];
+
+	/*
+	 * Make sure port is powered. If not, clear status and disable.
+	 * Note that POWER bit is different for USB 2.0 and 3.0 hubs.
+	 */
+	if (is_SS) {
+		if ((port_stat->wPortStatus & USB_SS_PORT_STAT_POWER) == 0) {
+			port_stat->wPortStatus = 0;
+			port_stat->wPortChange = 0;
+			set_link_state(roothub, USB_SS_PORT_LS_SS_DISABLED,
+				portnum);
+
+			goto update;
+		}
+	} else {
+		if ((port_stat->wPortStatus & USB_PORT_STAT_POWER) == 0) {
+			port_stat->wPortStatus = 0;
+			port_stat->wPortChange = 0;
+
+			goto update;
+		}
+	}
+
+	/* disconnect if previously connected */
+	if (do_connect == 0 || mhcd->disabled) {
+		if ((port_stat->wPortStatus & USB_PORT_STAT_CONNECTION) == 1) {
+			port_stat->wPortStatus &= ~(USB_PORT_STAT_CONNECTION);
+			port_stat->wPortStatus &= ~(USB_PORT_STAT_ENABLE);
+			port_stat->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+			if (is_SS)
+				set_link_state(roothub,
+					USB_SS_PORT_LS_RX_DETECT, portnum);
+		}
+	}
+	/* set bits for a new connection */
+	else if ((port_stat->wPortStatus & USB_PORT_STAT_CONNECTION) == 0) {
+		port_stat->wPortStatus |= USB_PORT_STAT_ENABLE;
+		port_stat->wPortStatus |= USB_PORT_STAT_CONNECTION;
+		port_stat->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+	}
+
+update:
+	mausb_dbg(mhcd, "%s: port status is 0x%x port change is 0x%x\n",
+		__func__, port_stat->wPortStatus, port_stat->wPortChange);
+
+	/* let core know if there is a change in port status */
+	if (port_stat->wPortChange) {
+		set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+		usb_hcd_poll_rh_status(hcd);
+	}
+
+	return portnum;
+}
+
+/**
+ * @mhcd:       MA USB hcd with connect/disconnect event.
+ * @portnum:	MA USB port number with event.
+ * @do_connect: Determines whether or not a connection is set or removed.
+ *
+ * Called to initiate either a device connect or disconnect event. A do_connect
+ * value of 0 clears a connection. A do_connect value greater than 0 sets a
+ * connection. A do_connect value less than 0 produces an error.
+ *
+ * Returns port number. If connection, port number is newly assigned port
+ * number, otherwise it is the port number passed in as an argument.
+ */
+int mausb_connect(struct mausb_hcd *mhcd, int portnum, int do_connect)
+{
+	struct usb_hcd		*hcd = container_of((void *)mhcd,
+					struct usb_hcd, hcd_priv);
+	struct usb_hcd		*ss_hcd = mhcd->shared_hcd;
+
+	if (!mhcd->ma_dev.ms_driver) {
+		mausb_err(mhcd, "%s: no media specific driver\n", __func__);
+		return -ENODEV;
+	}
+
+	if (do_connect < 0) {
+		mausb_err(mhcd, "%s: invalid connection request %d\n", __func__,
+			do_connect);
+		return -EINVAL;
+	}
+
+	if (mhcd->ma_dev.ma_cap.dev_type > MAUSB_DEV_TYPE_SS_HUB) {
+		mausb_err(mhcd, "%s: invalid MA USB device type %i\n", __func__,
+			mhcd->ma_dev.ma_cap.dev_type);
+		return -EINVAL;
+	}
+
+	/*
+	 * One connection event for MA devices. Connect SS and SS+ devices to
+	 * 3.0 root hub and non-SS devices to 2.0 root hub.
+	 */
+	else if (mhcd->ma_dev.ma_cap.dev_type == MAUSB_DEV_TYPE_INTEGRATED) {
+		if (!mhcd->ma_dev.speed) {
+			mausb_err(mhcd, "%s: Speed Capability Descriptor not"
+				" found - non-hub MA USB devices require"
+				" a Speed Capability Descriptor\n", __func__);
+			return -EPROTO;
+		}
+
+		mausb_dbg(mhcd, "%s: %s MA USB device\n", __func__,
+			do_connect ? "connecting" : "disconnecting");
+
+		if (mhcd->ma_dev.speed->speed == MAUSB_DEV_CAP_SPEED_SUPER ||
+		    mhcd->ma_dev.speed->speed == MAUSB_DEV_CAP_SPEED_SS_PLUS) {
+			portnum = port_connect(ss_hcd, do_connect, portnum,
+					       true);
+		} else {
+			portnum = port_connect(hcd, do_connect, portnum, false);
+		}
+	}
+
+	/*
+	 * Hubs require two connection events - one for the integrated
+	 * USB 3.0 hub and one for the integrated USB 2.0 hub.
+	 */
+	else {
+		mausb_dbg(mhcd, "%s: %s MA USB hub\n", __func__,
+			do_connect ? "connecting" : "disconnecting");
+
+		portnum = port_connect(hcd, do_connect, portnum, false);
+		portnum = port_connect(ss_hcd, do_connect, portnum, true);
+	}
+
+	return 0;
+}
+
+/**
+ * Called by usb core when polling for a port status change.
+ *
+ * @hcd:	USB HCD being polled.
+ * @buf:	Holds port status changes (if any).
+ *
+ * Returns zero if there is no status change, otherwise returns number of
+ * bytes in buf. When there is a status change on a port, the bit indexed
+ * at the port number + 1 (e.g. bit 2 for port 1) is set in the buffer.
+ */
+int mausb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	int                      i;
+	u16                      port_change = 0;
+	u32                      status = 0;
+	int                      ret = 1;
+	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	/*
+	 * Buf should never be more that 2 bytes. USB 3.0 hubs cannot have
+	 * more than 15 downstream ports.
+	 */
+	buf[0] = 0;
+	if (MAUSB_ROOTHUB_NUM_PORTS > 7) {
+		buf[1] = 0;
+		ret++;
+	}
+
+	for (i = 0; i < MAUSB_ROOTHUB_NUM_PORTS; i++) {
+		port_change = roothub->port_status[i].wPortChange;
+		if (port_change)
+			status |= (1 << (i + 1));
+	}
+
+	mausb_dbg(mhcd, "%s: hub status is 0x%x\n", __func__, status);
+
+	/* hcd might be suspended, resume if there is a status change */
+	if (mhcd->disabled == 0) {
+		if ((hcd->state == HC_STATE_SUSPENDED) && status)
+			usb_hcd_resume_root_hub(hcd);
+	}
+
+	memcpy(buf, (char *)&status, ret);
+
+	return status ? ret : 0;
+}
+
+/**
+ * Sets the bitfields in the hub descriptor of the 2.0 root hub. Always
+ * returns zero.
+ */
+int mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des)
+{
+	/* set the values to the default */
+	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
+	hub_des->bDescriptorType      = USB_DT_HUB;
+	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
+	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
+	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
+	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
+
+	return 0;
+}
+
+/**
+ * Sets the bitfields in the hub descriptor of the 3.0 root hub. Always
+ * returns zero.
+ */
+int mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des)
+{
+	/* set the values to the default */
+	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
+	hub_des->bDescriptorType      = USB_DT_SS_HUB;
+	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
+	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
+	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
+	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
+
+	/* USB3-specific parameters */
+	hub_des->u.ss.bHubHdrDecLat   = MAUSB_ROOTHUB_HDR_DEC_LAT;
+	hub_des->u.ss.wHubDelay       = MAUSB_ROOTHUB_DELAY;
+	hub_des->u.ss.DeviceRemovable = MAUSB_ALL_DEV_REMOVABLE;
+
+	return 0;
+}
+
+/**
+ * handles GetHubDescriptor requests to the root hub.
+ *
+ * @hcd:	USB HCD that owns root hub.
+ * @hub_des:    Hub descriptor to be copied.
+ * @wLength:    Maximum length that can be copied without overflowing
+ *		the buffer.
+ *
+ * Returns length of what was actually copied into the mausb hcd root hub
+ * descriptor. Note that this may be less than the total size of hub_des due
+ * to buffer size contraints.
+ */
+static int mausb_get_hub_descriptor(struct usb_hcd *hcd,
+		struct usb_hub_descriptor *hub_des, u16 wLength)
+{
+	struct mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	/* Don't overflow the buffer, and don't read more than you have. */
+	unsigned int cpyLength = min_t(u16, wLength,
+				       sizeof(struct usb_hub_descriptor));
+
+	if (mausb_is_ss_hcd(hcd))
+		memcpy(hub_des, &(mhcd->shared_root_hub.descriptor), cpyLength);
+	else
+		memcpy(hub_des, &(mhcd->root_hub.descriptor), cpyLength);
+
+	return cpyLength;
+}
+
+/**
+ * Handles requests to hub for the BOS.
+ *
+ * @ma_hcd:	MA USB HCD that owns hub.
+ * @bos:	MA USB BOS descriptor.
+ * @wLength:	Maximum length that can be copied without overflowing
+ *		the buffer.
+ *
+ * Returns length of what was actually copied into the MA USB hcd BOS
+ * descriptor. Note that this may be less than the total size of the BOS due
+ * to buffer size contraints.
+ */
+static int mausb_get_bos(struct mausb_hcd *ma_hcd,
+		struct mausb_host_bos *bos, u16 wLength)
+{
+	/* Don't overflow the buffer, and don't read more than you have. */
+	unsigned int cpyLength = min_t(u16, wLength,
+				       sizeof(struct mausb_host_bos));
+
+	memcpy(bos, &(ma_hcd->host_bos), cpyLength);
+
+	return cpyLength;
+}
+
+/**
+ * Initializes FS root hub port status values for a given MA USB roothub.
+ *
+ * All ports are initally powered and put in link state rx.detect to wait for
+ * a connection (or other event that changes link state). All other bits are
+ * cleared.
+ */
+int mausb_init_port_status(struct mausb_root_hub *mausb_rh)
+{
+	int	portnum = 0;
+
+	while (portnum < MAUSB_ROOTHUB_NUM_PORTS) {
+
+		/* set port power bit only */
+		mausb_rh->port_status[portnum].wPortStatus = 0x0;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_PORT_STAT_POWER;
+
+		/* make sure to start with no status changes */
+		mausb_rh->port_status[portnum].wPortChange = 0x0;
+		portnum++;
+	}
+
+	mausb_rh->rh_state = MAUSB_RH_RUNNING;
+
+	return 0;
+}
+
+/**
+ * Initializes SS root hub port status values for a given MA USb roothub.
+ *
+ * All ports are initally powered and put in link state rx.detect to wait for
+ * a connection (or other event that changes link state). All other bits are
+ * cleared.
+ */
+int mausb_init_ss_port_status(struct mausb_root_hub *mausb_rh)
+{
+	int	portnum = 0;
+
+	while (portnum < MAUSB_ROOTHUB_NUM_PORTS) {
+
+		/* set port power bit and put in link state rx.detect */
+		mausb_rh->port_status[portnum].wPortStatus = 0x0;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_SS_PORT_STAT_POWER;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_SS_PORT_LS_RX_DETECT;
+
+		/* make sure to start with no status changes */
+		mausb_rh->port_status[portnum].wPortChange = 0x0;
+		portnum++;
+	}
+
+	mausb_rh->rh_state = MAUSB_RH_RUNNING;
+
+	return 0;
+}
+
+/**
+ * Handles GetHubStatus request to root hub.
+ *
+ * @mhcd:	MA USB hcd that owns hub.
+ * @data:	Holds hub status to return to caller.
+ *
+ * Reads hub status from mhcd and gives it back to the caller via data.
+ * Returns the number of bytes copied into data.
+ */
+static int mausb_get_hub_status(struct usb_hcd *hcd, char *data)
+{
+	struct usb_hub_status   *hub_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	hub_stat = &roothub->status;
+	mausb_dbg(mhcd, "%s: hub status is 0x%x hub change is 0x%x\n",
+		__func__, hub_stat->wHubStatus, hub_stat->wHubChange);
+
+	((u16 *)data)[0] = cpu_to_le16(hub_stat->wHubStatus);
+	((u16 *)data)[1] = cpu_to_le16(hub_stat->wHubChange);
+
+	 return sizeof(hub_stat->wHubStatus) + sizeof(hub_stat->wHubChange);
+}
+
+/**
+ * Handles ClearHubFeature request to the root hub.
+ *
+ * @mhcd:	MA USB hcd that owns hub.
+ * @wValue:	Value that determines which feature is being cleared (see USB
+ *		3.0 spec for supported values).
+ *
+ * Returns 0 if sucessful, otherwise returns error to indicate invalid request.
+ */
+static int mausb_clear_hub_feature(struct usb_hcd *hcd, u16 wValue)
+{
+	int			err = 0;
+	struct usb_hub_status	*hub_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	hub_stat = &roothub->status;
+
+	switch (wValue) {
+	case C_HUB_LOCAL_POWER:
+		mausb_dbg(mhcd, "clearing HUB_LOCAL_POWER\n");
+		hub_stat->wHubChange &= ~(HUB_STATUS_LOCAL_POWER);
+		break;
+	case C_HUB_OVER_CURRENT:
+		mausb_dbg(mhcd, "clearing HUB_OVER_CURRENT\n");
+		hub_stat->wHubChange &= ~(HUB_STATUS_OVERCURRENT);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles GetPortStatus request to root hub.
+ *
+ * @mhcd:    	MA USB hcd that owns hub.
+ * @portnum:	Port number for which status is requested.
+ * @data:    	Holds port status to return to caller.
+ *
+ * Reads port status from mhcd and returns it to caller via data. Also
+ * completes a port reset.
+ *
+ * Returns the number of bytes copied into data.
+ */
+static int mausb_get_port_status(struct usb_hcd *hcd, int portnum, char *data)
+{
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	/*
+	 * Note: from USB core perspective ports are 1-indexed, mhcd uses
+	 * zero-indexing.
+	 */
+	port_stat = &roothub->port_status[portnum - 1];
+
+	/*
+	 * USB core sends a GetPortStatus request to complete a port reset.
+	 * After reset, port is enabled and link state is U0 (3.0 only).
+	 */
+	if (port_stat->wPortStatus & USB_PORT_STAT_RESET) {
+		port_stat->wPortStatus &= ~(USB_PORT_STAT_RESET);
+		port_stat->wPortStatus |= USB_PORT_STAT_ENABLE;
+
+		if (mausb_is_ss_hcd(hcd))
+			set_link_state(roothub, USB_SS_PORT_LS_U0, portnum - 1);
+	}
+
+	((u16 *)data)[0] = cpu_to_le16(port_stat->wPortStatus);
+	((u16 *)data)[1] = cpu_to_le16(port_stat->wPortChange);
+
+	mausb_dbg(mhcd, "%s: Port status is 0x%x Port change is 0x%x\n",
+		__func__, ((u16 *)data)[0], port_stat->wPortChange);
+
+	return sizeof(port_stat->wPortStatus) + sizeof(port_stat->wPortChange);
+}
+
+/**
+ * Handles SetPortFeature request to root hub.
+ *
+ * @mhcd:    	MA USB hcd that owns hub.
+ * @portnum:	Port number for which feature set is requested (port
+ *		number is from usb core perspective, i.e. not zero-indexed).
+ * @wValue:	Feature to be set (see USB 3.0 spec for supported values).
+ * @wIndex:	Contains link state to be set (ignored for requests other
+ *              than set link state).
+ *
+ * Sets the bit associated with a particular feature in the status bit field
+ * of the port specified by portnum. Note that ports are zero indexed in the
+ * hub, but indexed starting with one in the usb core (e.g. port 2 from the
+ * core's perspective is port 1 to the hub).
+ *
+ * Returns zero for all supported requests. Returns an error value if a feature
+ * is not supported.
+ */
+static int mausb_set_port_feature(struct usb_hcd *hcd, int portnum, u16 wValue,
+		u16 wIndex)
+{
+	int			err = 0;
+	u8			link_state = 0;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	port_stat = &roothub->port_status[portnum - 1];
+
+	switch (wValue) {
+	case USB_PORT_FEAT_RESET:
+		mausb_dbg(mhcd, "setting PORT_RESET feature\n");
+		port_stat->wPortStatus |= USB_PORT_STAT_RESET;
+		port_stat->wPortChange |= USB_PORT_STAT_C_RESET;
+		break;
+	case USB_PORT_FEAT_BH_PORT_RESET:
+		mausb_dbg(mhcd, "setting BH_PORT_RESET\n");
+		break;
+	case USB_PORT_FEAT_POWER:
+		mausb_dbg(mhcd, "setting PORT_POWER feature\n");
+		port_stat->wPortStatus |= USB_SS_PORT_STAT_POWER;
+		set_link_state(roothub, USB_SS_PORT_LS_RX_DETECT, portnum - 1);
+		break;
+	case USB_PORT_FEAT_U1_TIMEOUT:
+		mausb_dbg(mhcd, "setting PORT_U1_TIMEOUT\n");
+		break;
+	case USB_PORT_FEAT_U2_TIMEOUT:
+		mausb_dbg(mhcd, "setting PORT_U2_TIMEOUT\n");
+		break;
+	case USB_PORT_FEAT_LINK_STATE:
+		link_state = wIndex >> 8;
+		if (link_state == SS_DISABLED) {
+			mausb_dbg(mhcd, "setting link state to ss.disabled\n");
+			mhcd->disabled = 1;
+			clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+			set_link_state(roothub, USB_SS_PORT_LS_SS_DISABLED,
+				portnum - 1);
+			mausb_connect(mhcd, portnum - 1, 0);
+		}
+
+		else if (link_state == RX_DETECT) {
+			mausb_dbg(mhcd, "setting link state to rx.detect\n");
+			mhcd->disabled = 0;
+			set_link_state(roothub, USB_SS_PORT_LS_RX_DETECT,
+				portnum - 1);
+		}
+	break;
+	case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+		mausb_dbg(mhcd, "setting PORT_REMOTE_WAKE_MASK\n");
+	break;
+	case USB_PORT_FEAT_FORCE_LINKPM_ACCEPT:
+		mausb_dbg(mhcd, "setting FORCE_LINKPM_ACCEPT\n");
+	break;
+	default:
+		 err = -EINVAL;
+	break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles ClearPortFeature request to the root hub.
+ *
+ * @mhcd:     	MA USB hcd that owns hub.
+ * @portnum:	Port number for which feature clear is requested (port
+ *              number is from usb core perspective, i.e. not zero-indexed).
+ * @wValue:	Feature to clear (see USB 3.0 spec for supported values).
+ *
+ * Clears the bit associated with a particular feature in the status bit field
+ * of the port specified by portnum. Note that ports are zero indexed in the
+ * hub, but indexed starting with one in the usb core (e.g. port 2 from the
+ * core's perspective is port 1 to the hub).
+ *
+ * Returns zero for all supported requests. Returns an error value if a feature
+ * is not supported.
+ */
+static int mausb_clear_port_feature(struct usb_hcd *hcd, int portnum,
+		u16 wValue)
+{
+	int			 err = 0;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	port_stat = &roothub->port_status[portnum - 1];
+
+	switch (wValue) {
+	case USB_PORT_FEAT_POWER:
+		mausb_dbg(mhcd, "clearing PORT_POWER feature\n");
+		port_stat->wPortStatus &= ~(USB_SS_PORT_STAT_POWER);
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		mausb_dbg(mhcd, "clearing PORT_C_CONNECTION feature\n");
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_CONNECTION);
+		break;
+	case USB_PORT_FEAT_C_RESET:
+		mausb_dbg(mhcd, "clearing PORT_RESET feature\n");
+		port_stat->wPortStatus &= ~(USB_PORT_STAT_RESET);
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_RESET);
+		/* prevent excessive polling after reset */
+		clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		mausb_dbg(mhcd, "clearing PORT_OVER_CURRENT feature\n");
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_OVERCURRENT);
+	case USB_PORT_FEAT_C_PORT_LINK_STATE:
+	case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+	case USB_PORT_FEAT_C_BH_PORT_RESET:
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles getDescriptor requests to the roothub.
+ *
+ * @ma_hcd:	MA USB hcd that owns hub.
+ * @wValue:	Contains descriptor type in upper byte (see USB 3.0 spec for
+ *              descriptor types).
+ * @buf:	Holds descriptor to return to caller.
+ * @wLength:	Expected descriptor length.
+ *
+ * If successful, returns actual length of descriptor in buf. Otherwise returns
+ * error value.
+ */
+static int mausb_get_descriptor(struct mausb_hcd *ma_hcd, u16 wValue,
+		char *buf, u16 wLength)
+{
+	int	ret;
+
+	/*
+	 * per USB spec, section 9.4.3, the DT is contained in the upper byte
+	 * of wValue
+	 */
+	u8  bDesType = (wValue >> 8);
+
+	switch (bDesType) {
+	case USB_DT_DEVICE:
+		mausb_err(ma_hcd, "USB_DT_DEVICE not supported\n");
+		ret = -EPIPE;
+		break;
+	case USB_DT_CONFIG:
+		ret = 0;
+		break;
+	case USB_DT_BOS:
+		ret = mausb_get_bos(ma_hcd, (struct mausb_host_bos *) buf,
+			wLength);
+		mausb_dbg(ma_hcd, "%s: bos copied to buffer, wTotalLength %x\n",
+			__func__,
+			((struct mausb_host_bos *) buf)->bos_des.wTotalLength);
+		break;
+	case USB_DT_STRING:
+		ret = 0;
+		break;
+	default: /* invalid request */
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Handles requests from usb core to hub.
+ *
+ * @hcd:	USB hcd that owns hub.
+ * @typeReq:	Request type (see USB 3.0 spec for request types).
+ * @wValue:	Feature selector for hub/port feature requests,
+ *		descriptor type and index for hub descriptor requests,
+ *		hub depth for hub depth requests,zero for all other requests.
+ * @wIndex:	Port number for port requests, zero or language id for hub
+ *		descriptor requests, zero for all other requests.
+ * @buf:	Buffer for requested descriptor or status (if applicable).
+ * @wLength:	Descriptor length for descriptor requests, otherwise zero.
+ *
+ * Called by the USB core to make a request to the root hub. mausb_hub_control
+ * parses the request and routes it to the appropriate mausb helper function.
+ *
+ * If successful, returns descriptor length for descriptor request or zero for
+ * other requests. Otherwise returns error value.
+ */
+int mausb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+		u16 wIndex, char *buf, u16 wLength)
+{
+	int		err = 0;
+	int		portnum = (wIndex & 0xFF);
+	struct		mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (portnum > MAUSB_ROOTHUB_NUM_PORTS) {
+		mausb_err(mhcd, "port number %d is invalid\n", portnum);
+		return -EINVAL;
+	}
+
+	switch (typeReq) {
+	case MAUSB_REQ_GET_DES:
+		err = mausb_get_descriptor(usb_hcd_to_mausb_hcd(hcd),
+			wValue, buf, wLength);
+		err = sizeof(struct mausb_host_bos);
+		break;
+	case ClearHubFeature:
+		mausb_dbg(mhcd, "clearing hub feature %d\n", wValue);
+		err = mausb_clear_hub_feature(hcd, wValue);
+		break;
+	case ClearPortFeature:
+		mausb_dbg(mhcd, "clearing port %d feature %d\n", portnum,
+			wValue);
+		err = mausb_clear_port_feature(hcd, portnum, wValue);
+		break;
+	case GetHubDescriptor:
+		err = mausb_get_hub_descriptor(hcd,
+			(struct usb_hub_descriptor *) buf, wLength);
+		break;
+	case GetHubStatus:
+		mausb_dbg(mhcd, "getting hub status\n");
+		err = mausb_get_hub_status(hcd, buf);
+		break;
+	case GetPortStatus:
+		mausb_dbg(mhcd, "getting port %d status\n", portnum);
+		err = mausb_get_port_status(hcd, portnum, buf);
+		break;
+	/* SetHubFeature support is optional (only used for diagnostics) */
+	case SetHubFeature:
+		err = 0;
+		break;
+	case SetPortFeature:
+		mausb_dbg(mhcd, "setting port %d feature %d\n", portnum,
+			wValue);
+		mausb_set_port_feature(hcd, portnum, wValue, wIndex);
+		break;
+	case SetHubDepth:
+		err = 0;
+		break;
+	case GetPortErrorCount:
+		err = 0;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb driver");
diff --git a/drivers/staging/mausb/drivers/mausb_hub.h b/drivers/staging/mausb/drivers/mausb_hub.h
new file mode 100644
index 0000000..7670c1b
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hub.h
@@ -0,0 +1,128 @@
+/* name:	 mausb_hub.h
+ * description:  header file for mausb hub
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_HUB_H
+#define __MAUSB_HUB_H
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+
+/* root hub Parameters */
+#define MAUSB_ROOTHUB_CHAR (HUB_CHAR_LPSM | HUB_CHAR_INDV_PORT_OCPM)
+#define MAUSB_ROOTHUB_NUM_PORTS		1
+#define MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD 0
+#define MAUSB_ROOTHUB_CONTR_CURRENT     0
+#define MAUSB_ROOTHUB_HDR_DEC_LAT       0	/* < 0 uS */
+#define MAUSB_ROOTHUB_DELAY             0	/* 0 nS */
+#define MAUSB_ALL_DEV_REMOVABLE		0x0000  /* All devices are removable */
+
+/* per USB3 spec, section 9.4.3 */
+#define MAUSB_REQ_GET_DES (0x8000 | USB_REQ_GET_DESCRIPTOR)
+
+/* link state selectors for set_port_feature request to root hub */
+#define SS_DISABLED	4
+#define RX_DETECT	5
+
+/* mask used to clear port link state bits (bits 5-8) in wPortStatus */
+#define	LINK_STATE_MASK			0xFE1F
+
+/* forward declarations */
+struct mausb_root_hub;
+struct mausb_hcd;
+
+/* root hub states */
+enum mausb_rh_state {
+	MAUSB_RH_RESETTING,
+	MAUSB_RH_SUSPEND,
+	MAUSB_RH_RUNNING
+};
+
+/**
+ * Contains all the structures required to emulate a root hub. One instance
+ * exists per root hub.
+ */
+struct __attribute__((__packed__)) mausb_root_hub {
+
+	/* hub parameters */
+	struct usb_hub_descriptor descriptor;
+	struct usb_hub_status     status;
+
+	/* port parameters*/
+	struct usb_port_status    port_status[MAUSB_ROOTHUB_NUM_PORTS];
+
+	/* root hub state */
+	enum   mausb_rh_state     rh_state;
+
+};
+
+/* function declarations */
+bool    mausb_is_ss_hcd(struct usb_hcd *hcd);
+int	mausb_hub_status_data(struct usb_hcd *hcd, char *buf);
+int	mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des);
+int	mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des);
+int	mausb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+		u16 wIndex, char *buf, u16 wLength);
+int	mausb_init_port_status(struct mausb_root_hub *mausb_rh);
+int	mausb_init_ss_port_status(struct mausb_root_hub *mausb_rh);
+int	mausb_connect(struct mausb_hcd *hcd, int portnum, int do_connect);
+struct  mausb_root_hub *usb_hcd_to_roothub(struct usb_hcd *hcd);
+
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we create, store and handle endpoint and device structures
that are specific to the MA USB drivers. Each MA USB structure maps 1:1
with it's corresponding USB structure (e.g. there is one MA USB endpoint
per USB endpoint).

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_const.h    | 109 ++++
 drivers/staging/mausb/drivers/mausb_mem-host.c | 404 ++++++++++++
 drivers/staging/mausb/drivers/mausb_mem-host.h |  74 +++
 drivers/staging/mausb/drivers/mausb_mem.c      | 844 +++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_mem.h      | 509 +++++++++++++++
 drivers/staging/mausb/drivers/mausb_state.h    | 184 ++++++
 6 files changed, 2124 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_const.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_state.h

diff --git a/drivers/staging/mausb/drivers/mausb_const.h b/drivers/staging/mausb/drivers/mausb_const.h
new file mode 100755
index 0000000..1089f81
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_const.h
@@ -0,0 +1,109 @@
+/* Name:	mausb_const.h
+ * Description: This header describes the Media Agnostic USB constants
+ *              that must be known by the both the host and device side drivers.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_CONST_H
+#define __MAUSB_CONST_H
+
+/* MA USB protocol constants per Table 68 of the MA USB Spec */
+#define MAUSB_DATA_CHANNEL_DELAY	400	/* temp value */
+#define MAUSB_MGMT_CHANNEL_DELAY	((100 * HZ)/1000 + 1)
+#define MAUSB_MGMT_RESPONSE_DELAY	((5 * HZ)/1000 + 1) /* 5 msec */
+#define MAUSB_MGMT_RT_DELAY \
+	((MAUSB_MGMT_RESPONSE_DELAY + (2 * MAUSB_MGMT_CHANNEL_DELAY)))
+#define MAUSB_TRANSFER_RESPONSE_TIME	10	/* 10 msec */
+#define MAUSB_TRANSFER_TIMEOUT \
+	(MAUSB_TRANSFER_RESPONSE_TIME + (2 * MAUSB_DATA_CHANNEL_DELAY))
+#define MAUSB_TRANSFER_KEEP_ALIVE \
+	(MAUSB_TRANSFER_RESPONSE_TIME + MAUSB_DATA_CHANNEL_DELAY)
+#define MAUSB_DEFAULT_KEEP_ALIVE	 0
+#define MAUSB_MAX_TRANSFER_LIFETIME	 1000	/* 1 sec */
+#define MAUSB_TRANSFER_REPEAT_TIME	 10	/* 10 msec */
+
+#define MAUSB_MAX_REQ_ID		 ((1 << 8) - 1)
+#define MAUSB_MAX_SEQ_NUM		 ((1 << 24) - 1)
+#define MAUSB_MAX_DIALOG_TOKEN		 ((1 << 10) - 1)
+#define MAUSB_MIN_CONTROL_BUF_SIZE	 4104	/* Bytes */
+
+
+/* MA USB protocol variables per Table 69 of the MA USB Spec */
+#define MAUSB_BULK_TRANSFER_RETRIES	 10	/* min value is 5 */
+#define MAUSB_CONTROL_TRANSFER_RETRIES	 10	/* min value is 5 */
+#define MAUSB_INTERRUPT_TRANSFER_RETRIES 10	/* min value is 3 */
+#define MAUSB_MGMT_TRANSFER_RETRIES	 4      /* min value is 4 */
+#define MAUSB_TRANSFER_SETUP_RETRIES	 4	/* min value is 4 */
+
+
+/* MA USB constants not explicitly defined in MA USB Spec */
+#define MAUSB_HALF_REQ_ID		 ((MAUSB_MAX_REQ_ID + 1) >> 2)
+#define MAUSB_HALF_SEQ_NUM		 ((MAUSB_MAX_SEQ_NUM + 1) >> 2)
+#define MAUSB_MAX_OUTSTANDING_SEQ_NUM	 (1 << 23)
+
+/* Largest packet size (in bytes) that the medium can handle */
+#define MAUSB_MAX_PACKET_SIZE	300
+
+/* Used to parse get_status control requests */
+#define EP_REQ (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+#define EP_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+#define DEV_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define INTF_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Used for generating the mass_id for the device */
+#define MASS_ID_MIN	1
+#define MASS_ID_MAX	254
+
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_mem-host.c b/drivers/staging/mausb/drivers/mausb_mem-host.c
new file mode 100644
index 0000000..2cc54c9
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem-host.c
@@ -0,0 +1,404 @@
+/* Name:	mausb_mem-host.c
+ * Description: Contains hostside-specific memory functions, as well as
+ *              wrappers for functions in mausb_mem.c.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include <linux/kthread.h>
+
+#include "mausb_hcd.h"
+#include "mausb_mem-host.h"
+#include "mausb_mem.h"
+#include "mausb_tx.h"
+#include "mausb_mgmt.h"
+
+/**
+ * Returns a pointer to the media agnostic data for a given endpoint.
+ */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep)
+{
+	return (struct mausb_host_ep *) ep->hcpriv;
+}
+
+/**
+ * Returns the number of urbs currently in the MA USB HCD. Will return 0 if the
+ * MA USB HCD is empty or a negative errno if an error occurs.
+ */
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd)
+{
+	int			count = 0;
+	struct mausb_host_ep	*ma_ep;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_urb	*maurb;
+	unsigned long		irq_flags;
+
+	/* for every device */
+	spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &mhcd->ma_dev.dev_list, dev_list) {
+		spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+		/* for every endpoint */
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+		list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+			spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+			/* for every urb */
+			spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+			list_for_each_entry(maurb, &ma_ep->urb_list, urb_list) {
+				++count;
+			}
+
+			spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+			spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+		}
+
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	}
+
+	spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+	return count;
+}
+
+/**
+ * This function removes a device data from the hcd. All endpoints belonging
+ * to this device are also removed from the hcd and released (including EP0).
+ */
+void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev = mausb_find_dev_host(ma_dev, dev);
+	struct mausb_host_ep	*ep0 = list_first_entry(&mausb_dev->ep_list,
+					struct mausb_host_ep, ep_list);
+
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "%s: USB device #%i not found\n",
+			__func__, dev->devnum);
+		return;
+	}
+
+	ep0->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+
+	/* inactivate EP0 handle */
+	mausb_tx_dev_mgmt_req_ep(EPInactivateReq, &mhcd->ma_dev.mgmt,
+		mausb_dev, true, ep0);
+
+	/* delete remaining EP Handles */
+	mausb_tx_dev_mgmt_req(EPHandleDeleteReq, &mhcd->ma_dev.mgmt,
+		mausb_dev, MAUSB_HOST);
+
+	mausb_tx_dev_mgmt_req(USBDevDisconnectReq, &ma_dev->mgmt,
+		mausb_dev, MAUSB_HOST);
+
+	mausb_internal_free_dev(ma_dev, mausb_dev);
+
+	return;
+}
+
+/*
+ * Adds an endpoint to the specified device.
+ *
+ * This function allocates private endpoint data and adds the given endpoint
+ * to the given device. In the mausb_hcd, devices hold their endpoints in a
+ * linked list.
+ */
+int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep)
+{
+	int			status;
+	char			*ep_type;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_ms_drv	*ms_driver = ma_dev->ms_driver;
+	struct mausb_host_ep	*ma_ep;
+
+	/* don't need to do anything for root hub */
+	if ((NULL == dev->parent) && (&dev->ep0 != ep))
+		return 0;
+
+	mausb_dev = mausb_find_dev_host(ma_dev, dev);
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "unable to add endpoint: USB device #%i not"
+			" found\n", dev->devnum);
+		return -ENODEV;
+	}
+
+	status = mausb_internal_add_ep(mausb_dev, ep, NULL, &ma_ep,
+		&host_transfer_timeout, GFP_KERNEL);
+
+	if (status < 0) {
+		mausb_err(mhcd, "could not add endpoint: error %i\n", status);
+		return status;
+	}
+
+	/* need ms driver before adding endpoint */
+	if (NULL == ms_driver)
+		return -ENODEV;
+
+	/* for debug messages */
+	switch (usb_endpoint_type(&ep->desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ep_type = "control";
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ep_type = "bulk";
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ep_type = "interrupt";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		ep_type = "isochronous";
+		break;
+	default:
+		ep_type = "unknown";
+	}
+
+	/* set up control endpoint data channel */
+	if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_CONTROL) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_control_transferRequest);
+	}
+	/* set up bulk IN endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK
+		&& usb_endpoint_dir_in(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_IN_transferRequest);
+	}
+	/* set up bulk OUT endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK
+		&& usb_endpoint_dir_out(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_OUT_transferRequest);
+	}
+	/* set up an interrupt IN endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_INT
+		&& usb_endpoint_dir_in(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_IN_transferRequest);
+	}
+	/* set up an interrupt OUT endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_INT
+		&& usb_endpoint_dir_out(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_OUT_transferRequest);
+	} else {
+		mausb_err(mhcd,
+			"%s: attempted to add channel for ep %i of unsupported"
+			" type\n", __func__, usb_endpoint_num(&ep->desc));
+		return -EOPNOTSUPP;
+	}
+
+	if (status < 0) {
+		mausb_err(mhcd, "cannot add %s channel for ep %i: error %i\n",
+			ep_type, usb_endpoint_num(&ep->desc), status);
+		/* cleanup endpoint */
+		mausb_internal_drop_ep(ma_ep);
+	} else {
+		mausb_dbg(mhcd, "%s: added %s channel for ep %i\n", __func__,
+			ep_type, usb_endpoint_num(&ep->desc));
+	}
+
+	return status;
+}
+
+/*
+ * Removes an endpoint from the specified device.
+ *
+ * This function removes the given endpoint from the given device and releases
+ * private endpoint data. In the mausb_hcd, devices hold their endpoints in
+ * a linked list.
+ *
+ * TODO: determine & implement proper behavior when endpoint is not
+ *       associated with given device (or is associated with a different
+ *       device)
+ */
+int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep)
+{
+	int			ret = 0;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_host_ep	*ma_ep = usb_to_ma_endpoint(ep);
+	struct mausb_dev	*ma_dev;
+	struct mausb_urb	*ma_urb, *next_urb;
+	unsigned long		irq_flags;
+
+	if (NULL == ma_ep) {
+		mausb_err(mhcd, "%s: cannot find data for endpoint at %p\n",
+			__func__, ep);
+		return -ENODEV;
+	}
+
+	ma_dev = ma_ep->mausb_dev;
+
+	mausb_dbg(mhcd, "dropping endpoint at %p to USB device #%i\n", ep,
+		dev->devnum);
+
+	ret = mausb_tx_dev_mgmt_req_ep(CancelTransferReq, &mhcd->ma_dev.mgmt,
+		ma_dev, true, ma_ep);
+
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+
+	ret = mausb_tx_dev_mgmt_req_ep(EPInactivateReq, &mhcd->ma_dev.mgmt,
+		ma_dev, true, ma_ep);
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+	list_for_each_entry_safe(ma_urb, next_urb, &ma_ep->urb_list, urb_list) {
+
+		mausb_unlink_giveback_urb(ma_urb, -ECONNRESET);
+	}
+
+	if (!list_empty(&ma_ep->urb_list)) {
+		mausb_err(mhcd, "%s: could not drop all urbs for ma_ep at %p\n",
+			__func__, ma_ep->ep);
+	}
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * This function allocates a new device and adds it onto the MA device's linked
+ * list of usb devices. It also allocates endpoint data for the control
+ * endpoint (EP0).
+ *
+ * Returns 1 on success or 0 on failure.
+ */
+int mausb_alloc_dev(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	int			status = 0;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev;
+
+	mausb_dev = mausb_internal_alloc_dev(ma_dev, dev, NULL);
+	if (NULL == mausb_dev)
+		return 0;
+
+	/* add EP0 */
+	mausb_dbg(mhcd, "%s: adding EP0 . . .\n", __func__);
+	status = mausb_add_endpoint(hcd, dev, &dev->ep0);
+
+	/*
+	 * Don't add send the EP Request yet, usbcore hasn't set
+	 * the ep0 descriptor. Wait until a datapacket is sent.
+	 */
+
+	if (status >= 0)
+		return 1;
+
+	/* TODO: drop endpoint here if failure */
+	mausb_free_dev(hcd, dev);
+	mausb_err(mhcd, "%s: could not add EP0 %i\n", __func__, status);
+	return 0;
+}
+
+/**
+ * USB core calls the HCD's check_bandwidth function immediately after adding
+ * or deleting endpoints.
+ */
+int mausb_check_bandwidth(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	int			status;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev = mausb_find_dev_host(ma_dev, dev);
+
+	/* don't do anything if roothub */
+	if (NULL == dev->parent)
+		return 0;
+
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "%s: could not find data for USB device #%i\n",
+			__func__, dev->devnum);
+		return -ENODEV;
+	}
+
+	/* delete the old endpoints (if applicable) */
+	status = mausb_tx_dev_mgmt_req(EPHandleDeleteReq, &ma_dev->mgmt,
+					mausb_dev, MAUSB_HOST);
+
+	/* TODO: error checking (suppose the EPHandleDelete fails...) */
+
+	/* add the new endpoints (if applicable) */
+	status = mausb_tx_dev_mgmt_req(EPHandleReq, &ma_dev->mgmt, mausb_dev,
+		MAUSB_HOST);
+
+	if (-ENODEV == status) /* no endpoints were applicable */
+		status = 0;
+
+	return status;
+}
+
+/**
+ * This function will be called if mausb_add_endpoint(), mausb_drop_ep(),
+ * or mausb_check_bandwidth returns with an error. It is supposed to revert
+ * a device to a previously good schedule. We assume any schedule will work,
+ * so we should, in theory, never have to revert to a previous schedule.
+ */
+void mausb_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	mausb_dbg(usb_hcd_to_mausb_hcd(hcd),
+		"resetting bandwidth for USB edvice #%i\n", dev->devnum);
+	return;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_mem-host.h b/drivers/staging/mausb/drivers/mausb_mem-host.h
new file mode 100644
index 0000000..9df6c1f
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem-host.h
@@ -0,0 +1,74 @@
+/* Name:	mausb_mem-host.h
+ * Description: header for mausb_mem-host.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MEM_HOST_H
+#define __MAUSB_MEM_HOST_H
+
+/* endpoint/device helper functions */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep);
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd);
+
+/* USB core interfaces */
+int mausb_alloc_dev(struct usb_hcd *hcd, struct usb_device *dev);
+void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev);
+int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep);
+int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep);
+int mausb_check_bandwidth(struct usb_hcd *hcd, struct usb_device *dev);
+void mausb_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *dev);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_mem.c b/drivers/staging/mausb/drivers/mausb_mem.c
new file mode 100644
index 0000000..9f828d7
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem.c
@@ -0,0 +1,844 @@
+/* Name:	mausb_mem.c
+ * Description: Handles all of the dynamic data structures for the host
+ *              controller, including any data that needs to exist
+ *              on a per-device, per-endpoint, or per-transfer basis.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/kthread.h>
+
+#include "mausb_mem.h"
+#include "mausb_mgmt.h"
+#include "mausb_tx.h"
+#include "mausb_pkt.h"
+#include "mausb_const.h"
+#include "mausb_hcd.h"
+
+struct mausb_host_ep *mausb_state_to_ep(struct mausb_ep_state *state)
+{
+	return container_of(state, struct mausb_host_ep, state);
+}
+EXPORT_SYMBOL(mausb_state_to_ep);
+
+struct mausb_hcd *mausb_host_ep_to_mahcd(struct mausb_host_ep *ep)
+{
+	return ep->mausb_dev->ma_dev->mhcd;
+}
+EXPORT_SYMBOL(mausb_host_ep_to_mahcd);
+
+struct mausb_udc *mausb_host_ep_to_maudc(struct mausb_host_ep *ep)
+{
+	return ep->mausb_dev->ma_dev->maudc;
+}
+EXPORT_SYMBOL(mausb_host_ep_to_maudc);
+
+struct ma_dev *context_to_ma_dev(void *context)
+{
+	return (struct ma_dev *) context;
+}
+
+/*
+ * Finds the media-agnostic data for a given device.
+ *
+ * @ma_dev:	The MA USB device the USB device is located behind.
+ * @dev:	The USB device to find.
+ * @handle:	The MA USB device handle of USB device to find.
+ * @gadget:	The USB gadget device to find.
+ *
+ * Returns a pointer to the media agnostic data for a USB device given one or
+ * more parameters. Returns NULL if the device cannot be found.
+ */
+struct mausb_dev *mausb_find_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, unsigned long *handle,
+		struct usb_gadget *gadget)
+{
+	struct mausb_dev *mausb_dev;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &ma_dev->dev_list, dev_list) {
+
+		/* if found */
+		if ((NULL != dev && mausb_dev->dev == dev) ||
+			(NULL != gadget && mausb_dev->gadget == gadget) ||
+			(NULL != handle && mausb_dev->dev_handle == *handle)) {
+			spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+			return mausb_dev;
+		}
+	}
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	/* device not found */
+	return NULL;
+}
+
+struct mausb_dev *mausb_find_dev_host(struct ma_dev *ma_dev,
+		struct usb_device *dev)
+{
+	return mausb_find_dev(ma_dev, dev, NULL, NULL);
+}
+EXPORT_SYMBOL(mausb_find_dev_host);
+
+/**
+ * Returns true if usb_endpoint descriptors are the same.
+ */
+static bool mausb_ep_desc_eq(const struct usb_endpoint_descriptor *desc1,
+		const struct usb_endpoint_descriptor *desc2)
+{
+	return ((desc1->bLength == desc2->bLength)
+		&& (desc1->bDescriptorType  == desc2->bDescriptorType)
+		&& (desc1->bEndpointAddress == desc2->bEndpointAddress)
+		&& (desc1->bmAttributes     == desc2->bmAttributes)
+		&& (desc1->wMaxPacketSize   == desc2->wMaxPacketSize));
+}
+
+/**
+ * Finds the media agnostic data for an endpoint given one or more parameters.
+ *
+ * @ep:			USB host endpoint to find MA USB endpoint for.
+ * @dev_ep:		USB device endpoint to find MA USB endpoint for.
+ * @handle:		Endpoint handle of MA USB endpoint.
+ * @mausb_dev:		The MA USB device the endpoint belongs to.
+ * @ep_desc:		endpoint descriptor for USB endpoint.
+ * @address:		MA USB endpoint address.
+ *
+ * Returns a pointer to the media agnostic data for the endpoint or NULL if
+ * the device cannot be found.
+ */
+static struct mausb_host_ep *mausb_find_ep(struct usb_host_endpoint *ep,
+		struct usb_ep *dev_ep, struct mausb_ep_handle *handle,
+		struct mausb_dev *mausb_dev,
+		const struct usb_endpoint_descriptor *ep_desc,
+		u8 address)
+{
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+
+		/* if found */
+		if ((NULL != dev_ep && ma_ep->dev_ep == dev_ep) ||
+			(NULL != ep && ma_ep->ep == ep) ||
+			(NULL != handle
+			 && ma_ep->ep_handle_state != MAUSB_EP_HANDLE_UNASSIGNED
+			 && ma_ep->ep_handle.handle == handle->handle) ||
+			(NULL != ep_desc && NULL != ma_ep->ep
+			 && mausb_ep_desc_eq(ep_desc, &ma_ep->ep->desc)) ||
+			(NULL != ep_desc && NULL != ma_ep->dev_ep &&
+			 NULL != ma_ep->dev_ep->desc
+			 && mausb_ep_desc_eq(ep_desc, ma_ep->dev_ep->desc)) ||
+			(address != 0 && NULL != ma_ep->dev_ep &&
+			 address == ma_ep->dev_ep->address)) {
+
+			spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+			return ma_ep;
+		}
+	}
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	/* endpoint not found */
+	return NULL;
+}
+
+struct mausb_host_ep *mausb_find_ep_dev(struct usb_ep *dev_ep,
+			struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(NULL, dev_ep, NULL, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_dev);
+
+struct mausb_host_ep *mausb_find_ep_host(struct usb_host_endpoint *ep,
+	struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(ep, NULL, NULL, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_host);
+
+struct mausb_host_ep *mausb_find_ep_by_desc(
+	const struct usb_endpoint_descriptor *ep_desc,
+	struct mausb_dev *mausb_dev)
+
+{
+	return mausb_find_ep(NULL, NULL, NULL, mausb_dev, ep_desc, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_desc);
+
+struct mausb_host_ep *mausb_find_ep_by_handle(struct mausb_ep_handle *handle,
+	struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(NULL, NULL, handle, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_handle);
+
+struct mausb_host_ep *mausb_find_ep_by_address(u8 address,
+	struct mausb_dev *mausb_dev)
+
+{
+	return mausb_find_ep(NULL, NULL, NULL, mausb_dev, NULL, address);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_address);
+
+struct mausb_host_ep *mausb_find_ep_from_handle(struct mausb_ep_handle handle,
+	struct ma_dev *ma_dev)
+{
+	struct mausb_host_ep *ma_ep;
+	struct mausb_dev *mausb_dev;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &ma_dev->dev_list, dev_list) {
+		spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+		ma_ep = mausb_find_ep_by_handle(&handle, mausb_dev);
+		if (ma_ep != NULL)
+			return ma_ep;
+
+		spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	}
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	return NULL;
+}
+
+/**
+ * Wrapper function to be used by devices when they want to generate an
+ * ma packet.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ma_dev(struct ms_pkt *ms_pkt,
+	struct ma_dev *ma_dev, gfp_t mem_flags)
+{
+	return mausb_pkt_from_ms_pkt(ms_pkt,
+			ma_dev->ms_driver->ops->pkt_destructor, mem_flags);
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt_ma_dev);
+
+/**
+ * Wrapper to be used by endpoints when they want to generate an ma packet.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ep(struct ms_pkt *ms_pkt,
+	struct mausb_host_ep *ep, gfp_t mem_flags)
+{
+	return mausb_pkt_from_ms_pkt_ma_dev(ms_pkt, ep->mausb_dev->ma_dev,
+		mem_flags);
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt_ep);
+
+const struct usb_endpoint_descriptor *mausb_get_ep_des(
+		struct mausb_host_ep *ma_ep)
+{
+	if ((NULL != ma_ep->ep && NULL != ma_ep->dev_ep) ||
+	    (NULL == ma_ep->ep && NULL == ma_ep->dev_ep)) {
+
+		mamem_err("%s: ERROR: ep = 0x%p, dev_ep = 0x%p "
+			"(only one should be set)\n", __func__,
+			ma_ep->ep, ma_ep->dev_ep);
+
+		return NULL;
+	}
+
+	if (NULL != ma_ep->ep)
+		return &ma_ep->ep->desc;
+
+	if (NULL != ma_ep->dev_ep)
+		return ma_ep->dev_ep->desc;
+
+	/* We should never get here */
+	BUG();
+	return NULL;
+}
+EXPORT_SYMBOL(mausb_get_ep_des);
+
+/**
+ * Fills an MA USB packet header for the given maurb
+ */
+static int fill_mausb_dph(struct mausb_dph *ma_pkt, struct mausb_urb *maurb,
+		  bool in, bool host)
+{
+	const struct usb_endpoint_descriptor *ep_des;
+	unsigned long irq_flags;
+
+	/* set the version number */
+	ma_pkt->common.ver_flags =  MAUSB_VERSION_1_0 & MAUSB_VERSION_MASK;
+
+	/* set the host flag if from the host */
+	ma_pkt->common.ver_flags |= host ? MAUSB_PKT_FLAG_HOST : 0;
+
+	/* set the device handle field */
+	spin_lock_irqsave(&maurb->ep->ep_lock, irq_flags);
+	ma_pkt->common.ep_handle = maurb->ep->ep_handle;
+	spin_unlock_irqrestore(&maurb->ep->ep_lock, irq_flags);
+
+	ma_pkt->common.pkt_status = SUCCESS;
+
+	ep_des = mausb_get_ep_des(maurb->ep);
+
+	/* set transfer type in tflags field */
+	switch (usb_endpoint_type(ep_des)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_CTRL;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_ISOC;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_BULK;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_INT;
+		break;
+	default:
+		mamem_err("%s: invalid transfer type\n", __func__);
+	}
+
+	return 0;
+}
+
+/**
+ * Create a datapacket from a given URB.
+ */
+struct mausb_pkt *mausb_create_dp(int *status, struct mausb_urb *maurb,
+	bool in, bool host, gfp_t memflags)
+{
+	struct mausb_pkt	*pkt;
+	int			ret = 0;
+
+	pkt = mausb_alloc_pkt(MAUSB_PKT_TYPE_DATA, status, memflags);
+	if (NULL == pkt) {
+		mamem_err("%s:failed to allocate memory for mausb packet\n",
+			__func__);
+
+		if (NULL != status)
+			*status = -ENOMEM;
+
+		return NULL;
+	}
+
+	ret = fill_mausb_dph(pkt->data, maurb, in, host);
+	INIT_LIST_HEAD(&pkt->pkt_list);
+	if (NULL != status)
+		*status = ret;
+
+	return pkt;
+}
+EXPORT_SYMBOL(mausb_create_dp);
+
+struct mausb_urb *mausb_alloc_maurb(struct mausb_host_ep *ma_ep, gfp_t memflags)
+{
+	struct mausb_urb     *maurb;
+
+	maurb = kzalloc(sizeof(struct mausb_urb), memflags);
+	if (!maurb)
+		return NULL;
+
+	INIT_LIST_HEAD(&maurb->urb_list);
+	maurb->ep = ma_ep;
+	maurb->dev = ma_ep->mausb_dev;
+
+	return maurb;
+}
+EXPORT_SYMBOL(mausb_alloc_maurb);
+
+/**
+ * Deletes the given maurb and removes all pointers to it from memory.
+ */
+int mausb_internal_drop_maurb(struct mausb_urb *maurb, struct mausb_hcd *mhcd)
+{
+	struct mausb_host_ep *ep = maurb->ep;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	list_del(&maurb->urb_list);
+	if (maurb == ep->active_transfer)
+		ep->active_transfer = NULL;
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+	list_del(&maurb->ma_hcd_urb_list);
+	spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+	/*
+	 * Nobody else should know this maurb exists, so it should be
+	 * safe to free
+	 */
+	kfree(maurb);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_drop_maurb);
+
+/**
+ * Sets endpoint state to default.
+ *
+ * @state:	State of endpoint to be configured.
+ * @buf_size:	The maximum number of Bytes the device-side buffer
+ *              can receive from the host.
+ *
+ * Called whenever an MA USB endpoint is configured and needs to be set
+ * or reset to its initial state.
+ */
+void init_ep_state(struct mausb_ep_state *state, u32 buf_size)
+{
+	state->request_id = 0;
+	state->active_request_id = 0;
+	state->seq_number = 0;
+	state->tx_pending = 0;
+	state->earliest_request_id = 0;
+	state->earliest_unacked = 0;
+	state->occupancy = 0;
+	state->rx_buf_size = buf_size;
+	state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+	state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	/* TODO: number of retries depends on transfer type, include
+	 * other transfer types (control and interrupt) */
+}
+
+struct mausb_gadget_ep *usb_ep_to_mausb_gadget_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct mausb_gadget_ep, dev_ep);
+}
+EXPORT_SYMBOL(usb_ep_to_mausb_gadget_ep);
+
+/**
+ * Links a Device-side endpoint to an MA USB endpoint
+ */
+void mausb_link_ma_ep_to_usb_ep(struct mausb_host_ep *ma_ep,
+		struct usb_ep *dev_ep)
+{
+	struct mausb_gadget_ep *gadget_ep = usb_ep_to_mausb_gadget_ep(dev_ep);
+
+	ma_ep->dev_ep = dev_ep;
+	ma_ep->halted = 0;
+	ma_ep->wedged = 0;
+
+	ma_ep->usb_req_list = &gadget_ep->usb_req_list;
+}
+EXPORT_SYMBOL(mausb_link_ma_ep_to_usb_ep);
+
+/*
+ * Adds an endpoint to the specified device.
+ *
+ * @ma_dev:		The usb device to add the endpoint to.
+ * @ep/dev_ep:		The usb struct for the endpoint being added.
+ *			Note: give only one of the endpoint pointers and
+ *                      set the other to NULL.
+ * @mausb_ep:		The mausb_ep struct created by this function.
+ * @transfer_timeout:	The transfer timeout function. A thread will be
+ *                      spawned with this function for handling timeouts.
+ *
+ * Adds the given endpoint to the given device. The difference between this
+ * function and mausb_add_endpoint (which can be called from the usb core)
+ * is that this uses the private ma-structs. Calling this function is
+ * cheaper, and therefore preferred when possible, since mausb_add_endpoint
+ * will have to find the internal structures.
+ */
+int mausb_internal_add_ep(struct mausb_dev *ma_dev,
+		struct usb_host_endpoint *ep, struct usb_ep *dev_ep,
+		struct mausb_host_ep **mausb_ep,
+		int (*transfer_timeout)(void *data), gfp_t memflags)
+{
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	ma_ep = kzalloc(sizeof(struct mausb_host_ep), memflags);
+	if (!ma_ep)
+		return -ENOMEM;
+
+	/* host operations */
+	if (ep != NULL) {
+		ep->hcpriv = ma_ep;
+		ma_ep->ep = ep;
+
+	/* device operations */
+	} else if (dev_ep != NULL)
+		mausb_link_ma_ep_to_usb_ep(ma_ep, dev_ep);
+
+	ma_ep->mausb_dev = ma_dev;
+
+	/* set initial EP State */
+	init_ep_state(&ma_ep->state, DEVICE_RX_BUF_SIZE);
+
+	/*
+	 * only used by full speed devices to determine if the max packet
+	 * size has changed for EP0
+	 */
+	ma_ep->max_pkt = 8;
+
+	/* initialize mausb_ep_handle */
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_UNASSIGNED;
+
+	INIT_LIST_HEAD(&ma_ep->urb_list);
+	INIT_LIST_HEAD(&ma_ep->ep_list);
+	INIT_LIST_HEAD(&ma_ep->req_list);
+	INIT_LIST_HEAD(&ma_ep->resp_list);
+
+	spin_lock_init(&ma_ep->ep_lock);
+	ma_ep->tx_timed_out = false;
+
+	/* initialize endpoint work queue */
+	init_waitqueue_head(&ma_ep->host_ep_wq);
+
+	/* initialize endpoint timer */
+	setup_timer(&ma_ep->timer, wake_timeout_thread, (unsigned long) ma_ep);
+
+	/* add the endpoint to the device */
+	spin_lock_irqsave(&ma_dev->dev_lock, irq_flags);
+	list_add_tail(&ma_ep->ep_list, &ma_dev->ep_list);
+	spin_unlock_irqrestore(&ma_dev->dev_lock, irq_flags);
+
+	/* give a pointer to the ma_ep back to the caller */
+	if (NULL != mausb_ep)
+		*mausb_ep = ma_ep;
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_add_ep);
+
+/**
+ * Drops the given endpoint from the given device. The difference between this
+ * function and mausb_drop_endpoint (which can be called from the usb core)
+ * is that this uses the private ma-structs. Calling this function is
+ * cheaper, and therefore preferred when possible, since mausb_drop_endpoint
+ * will have to find the internal endpoint structure.
+ */
+int mausb_internal_drop_ep(struct mausb_host_ep *ma_ep)
+{
+	struct mausb_dev *ma_dev;
+	struct mausb_request  *ma_request, *next_request;
+	struct mausb_pkt *ma_pkt, *next_pkt;
+	unsigned long     irq_flags;
+	unsigned long     irq_flags2;
+
+	if (NULL == ma_ep)
+		return -EINVAL;
+
+	/* drop all pending transfers */
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+	ma_dev = ma_ep->mausb_dev;
+
+	/* stop transfer timeout thread */
+	if (NULL != ma_ep->timeout_task)
+		kthread_stop(ma_ep->timeout_task);
+
+	/* drop all pending usb_requests (if there are any) */
+	if (NULL != ma_ep->usb_req_list) {
+		list_for_each_entry_safe(ma_request, next_request,
+					ma_ep->usb_req_list, usb_req_list) {
+			list_del(&ma_request->usb_req_list);
+			ma_request->req.status = -ESHUTDOWN;
+			ma_request->req.complete(ma_ep->dev_ep,
+							&ma_request->req);
+		}
+	}
+
+	/* flush out all of the stored request/response packets */
+	list_for_each_entry_safe(ma_pkt, next_pkt, &ma_ep->req_list, pkt_list) {
+		list_del(&ma_pkt->pkt_list);
+		mausb_free_pkt(ma_pkt);
+	}
+	list_for_each_entry_safe(ma_pkt, next_pkt,
+					&ma_ep->resp_list, pkt_list) {
+		list_del(&ma_pkt->pkt_list);
+		mausb_free_pkt(ma_pkt);
+	}
+
+	/* remove the endpoint from the list */
+	spin_lock_irqsave(&ma_dev->dev_lock, irq_flags2);
+	list_del(&ma_ep->ep_list);
+	spin_unlock_irqrestore(&ma_dev->dev_lock, irq_flags2);
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	kfree(ma_ep);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_drop_ep);
+
+/**
+ * Updates the state of an endpoint based on the mausb_ep_des.
+ */
+int mausb_update_ep(struct mausb_host_ep *ma_ep,
+			struct mausb_ep_des *ma_ep_des)
+{
+	unsigned long     irq_flags;
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	if (!ma_ep_des->valid) { /* Valid bit: 0 means valid */
+		ma_ep->ep_handle.handle = ma_ep_des->ep_handle.handle;
+		ma_ep->ep_handle_state = MAUSB_EP_HANDLE_ACTIVE;
+	}
+
+	if (ma_ep_des->dir == 0) {
+		ma_ep->state.rx_buf_size = ma_ep_des->buffer_size;
+
+
+		if (ma_ep_des->l_man)
+			ma_ep->lman_support = true;
+		else
+			ma_ep->lman_support = false;
+	}
+
+	/*TODO: parse and use the remainder of the values in the packet */
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Allocates private per-usb-device data.
+ *
+ * @ma_dev:	The MA USB device to which the USB device belongs
+ * @usb_dev:	The host-side USB device struct to add.
+ * @gadget:	The device-side USB device struct to add.
+ *
+ * This function allocates a new device and adds it onto the MA USB device's
+ * linked list of usb devices. It also allocates endpoint data for the control
+ * endpoint (EP0).
+ */
+struct mausb_dev *mausb_internal_alloc_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, struct usb_gadget *gadget)
+{
+	unsigned long     irq_flags;
+	struct mausb_dev *mausb_dev;
+
+	mausb_dev = kzalloc(sizeof(struct mausb_dev), GFP_KERNEL);
+
+	if (!mausb_dev)
+		return NULL;
+
+	if (NULL != dev)
+		mausb_dev->dev = dev;
+	if (NULL != gadget)
+		mausb_dev->gadget = gadget;
+	mausb_dev->ma_dev = ma_dev;
+	INIT_LIST_HEAD(&mausb_dev->ep_list);
+	INIT_LIST_HEAD(&mausb_dev->dev_list);
+	spin_lock_init(&mausb_dev->dev_lock);
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+
+	/*
+	 * If this is the first device to be allocated, then it should be the
+	 * most upstream.
+	 */
+	if (NULL == ma_dev->top_dev)
+		ma_dev->top_dev = mausb_dev;
+
+	list_add_tail(&mausb_dev->dev_list, &ma_dev->dev_list);
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	return mausb_dev;
+}
+EXPORT_SYMBOL(mausb_internal_alloc_dev);
+
+/**
+ * Frees private per-device data.
+ *
+ * @ma_dev:	The MA USB device that the USB device beingfreed belongs to.
+ * @mausb_dev:	The MA USB data associated with the USB device being freed.
+ *
+ * This function removes a USB device from the MA USB hcd's linked list
+ * and releases the device's media agnostic data structure. All endpoints
+ * belonging to this device are also removed from the MA USB hcd and released
+ * (including EP0).
+ */
+int mausb_internal_free_dev(struct ma_dev *ma_dev, struct mausb_dev *mausb_dev)
+{
+	int			ret = 0;
+	unsigned long		irq_flags, irq_flags2;
+	struct mausb_host_ep	*ma_ep, *next;
+
+	/* remove all the endpoints from the device */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry_safe(ma_ep, next, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		ret = mausb_internal_drop_ep(ma_ep);
+
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	if (!list_empty(&mausb_dev->ep_list)) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		return ret;
+	}
+
+	/* remove the mausb device from the ma device */
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags2);
+	list_del(&mausb_dev->dev_list);
+
+	/* if the top device is being removed */
+	if (ma_dev->top_dev == mausb_dev)
+		ma_dev->top_dev = NULL;
+
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags2);
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	kfree(mausb_dev);
+
+	return ret;
+
+}
+EXPORT_SYMBOL(mausb_internal_free_dev);
+
+/**
+ * Resets all the data in a ma_dev struct. This includes freeing all the MA
+ * data for the usb devices and endpoints connected to this device.
+ */
+int mausb_internal_reset_ma_dev(struct ma_dev *ma_dev, __u8 ma_dev_addr,
+	__u8 mass_id, struct mausb_hcd *mhcd, struct mausb_udc *maudc)
+{
+	int			ret = -EINVAL;
+	struct mausb_dev	*mausb_dev, *mausb_next;
+	int (*req_switch)(struct mausb_mgmt_pkt *req,
+			  struct mausb_mgmt_pkt *resp,
+			  struct mausb_mgmt *mgmt)
+		= ma_dev->mgmt.req_switch;
+	int (*device_connect)(int) = ma_dev->ma_drv.device_connect;
+	unsigned long irq_flags;
+
+	if (NULL != mhcd)
+		ma_dev->mhcd = mhcd;
+
+	if (NULL != maudc)
+		ma_dev->maudc = maudc;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry_safe(mausb_dev, mausb_next, &ma_dev->dev_list,
+				dev_list) {
+		spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+		ret = mausb_internal_free_dev(ma_dev, mausb_dev);
+
+		spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	}
+
+	if (!list_empty(&ma_dev->dev_list)) {
+		/* could not clear all the devices */
+		ret = -EAGAIN;
+	}
+
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	/* TODO: make sure this doesn't break any locking rules */
+	mausb_init_ma_device(ma_dev, ma_dev_addr, mass_id, mhcd,
+			     maudc, req_switch, device_connect);
+
+	return ret;
+}
+
+/**
+ * Initializes the media agnostic management structure.
+ */
+int mausb_init_mgmt(struct mausb_mgmt *mgmt, spinlock_t *ma_dev_lock,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt))
+{
+	INIT_LIST_HEAD(&mgmt->req_list);
+	mgmt->token = 0;
+	mgmt->tx_pair.to_ms.context = NULL;
+	mgmt->tx_pair.to_ms.transfer_packet = NULL;
+	mgmt->tx_pair.to_ma.context = NULL;
+	mgmt->tx_pair.to_ma.transfer_packet = NULL;
+	mgmt->hub_dev_handle = 0;
+	mgmt->ma_dev_lock = ma_dev_lock;
+	mgmt->req_switch = req_switch;
+
+	return 0;
+}
+
+static void mausb_init_pkt_dmux(struct mausb_pkt_transfer *pkt_dmux,
+		void *context)
+{
+	pkt_dmux->transfer_packet = &mausb_pkt_dmux;
+	pkt_dmux->context = context;
+}
+
+/*
+ * Initializes the data structure for an MA USB device.
+ */
+int mausb_init_ma_device(struct ma_dev *ma_dev, __u8 ma_dev_addr, __u8 mass_id,
+		struct mausb_hcd *mhcd, struct mausb_udc *maudc,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt),
+		int (*device_connect)(int))
+{
+	INIT_LIST_HEAD(&ma_dev->dev_list);
+	ma_dev->top_dev = NULL;
+	ma_dev->ma_dev_addr = ma_dev_addr;
+	ma_dev->mass_id = mass_id;
+	if (mhcd != NULL)
+		ma_dev->mhcd = mhcd;
+	if (maudc != NULL)
+		ma_dev->maudc = maudc;
+	spin_lock_init(&ma_dev->ma_dev_lock);
+	ma_dev->ma_drv.device_connect = device_connect;
+	mausb_init_pkt_dmux(&ma_dev->ma_drv.pkt_dmux, ma_dev);
+
+	mausb_init_mgmt(&ma_dev->mgmt, &ma_dev->ma_dev_lock, req_switch);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_init_ma_device);
+
diff --git a/drivers/staging/mausb/drivers/mausb_mem.h b/drivers/staging/mausb/drivers/mausb_mem.h
new file mode 100644
index 0000000..870591f
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem.h
@@ -0,0 +1,509 @@
+/* Name:	mausb_mem.h
+ * Description: Header for mausb_mem.c. Needed do make calls to
+ *              functions defined in mausb_mem.c.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MEM_H
+#define __MAUSB_MEM_H
+
+#include "mausb_state.h"
+#include "mausb_pkt.h"
+#include "mausb_msapi.h"
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/gadget.h>
+#include <linux/timer.h>
+
+#ifdef DEBUG
+#define mamem_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mamem_dbg(format, arg...)
+#endif
+
+#define mamem_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mamem_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* forward declarations */
+struct mausb_urb;
+struct mausb_pkt;
+struct mausb_host_ep;
+
+/**
+ * mausb_mgmt - MAUSB management datastrucure
+ *
+ * Contains all the data necessary to handle management packets.
+ *
+ * @req_list:		List of all currently pending management requests for
+ *			this device.
+ * @token:		The value of the token field in the most recently sent
+ *			management request.
+ * @tx_pair:		Indicates where management packets should be sent.
+ *
+ * The following variables are to store common management packet fields:
+ *
+ * @hub_dev_handle:	Device Handle of the MAUSB Dock hub. used for
+ *                  	USBDevHandleReq packets.
+ * @ma_dev_lock:	The spinlock which protects the management data in this
+ *			struct.
+ * @req_switch:		The host or devices request switch. It accepts an
+ * 			incoming request, makes the necessary calls, and
+ *			returns a partially completed response (it fills the
+ *			response type, status & any data fields specific to
+ *			that response). the remainder of the fields are
+ *			completed by mausb_rx_mgmt_req.
+ */
+struct mausb_mgmt {
+	struct list_head		req_list;
+	__u16				token:10;
+	struct mausb_transfer_pair	tx_pair;
+	__u16				hub_dev_handle;
+	spinlock_t			*ma_dev_lock;
+	int (*req_switch)(struct mausb_mgmt_pkt *req,
+			struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt);
+};
+
+/**
+ * mausb_mgmt_req_list - MAUSB management request list entry
+ *
+ * An entry in the mausb_mgmt request linked list.
+ *
+ * @req_list:	Pointers to other entries in the list.
+ * @mgmt_req:	The request management packet.
+ * @mgmt_resp:	The response management packet, set to NULL until a response
+ *		is received.
+ * @resp_rcvd:	An event triggered when the response is received.
+ */
+struct mausb_mgmt_req_list {
+	struct list_head	req_list;
+
+	struct mausb_pkt	*mgmt_req;
+	struct mausb_pkt	*mgmt_resp;
+
+	struct completion	resp_rcvd;
+};
+
+/**
+ * Media Agnostic Session State
+ *
+ * Defines the current state of the session between the host & device.
+ * Per MAUSB spec, sections 7.1 & 8.1.1.
+ */
+enum mausb_session_state {
+	MAUSB_SESSION_DOWN,
+	MAUSB_SESSION_CONNECTING,
+	MAUSB_SESSION_ACITVE,
+	MAUSB_SESSION_INACTIVE
+};
+
+/**
+ * stores information returned in a CapResp packet
+ */
+struct ma_capability {
+	__u16		num_ep;
+	__u8		num_dev;
+	__u8		num_stream:5;
+	__u8		dev_type:3;
+	__u16		max_tx_reqs;
+	__u16		max_mgmt_reqs:12;
+};
+
+/**
+ * MA device data
+ *
+ * This structure is used to hold MA device-specific data
+ * (i.e. one instance of this structure exists per MA device).
+ *
+ * @mgmt:		Contains the data needed to keep track of the device's
+ *			management packets.
+ * @dev_list:		Stores a list of the devices connected to this HCD.
+ *			This includes any internal mausb data that exists on
+ *			a per-device, per-endpoint, or per-transfer basis.
+ * @top_dev:		The most upstream mausb device. Used to determine
+ *			where to send MA USB device management packets (such as
+ *			MAUSBDevSleepReq and MAUSBDevWakeReq).
+ * @session_state:	Defines the current state of the session between the
+ *			host and device. Per MAUSB spec, sections 7.1 & 8.1.1.
+ * @ma_dev_addr: 	MA Device Address. Assigned by the host via a
+ *               	MAUSBDevResetReq.
+ * @mass_id:		Media-Agnostic Service Set Identifier. Assigned by the
+ *			host via a MAUSBDevResetReq.
+ * @ma_dev_lock:	Spinlock for this device. This lock should be held
+ *			before accessing any data in this structure.
+ * @ma_drv:		Media agnostic driver interfaces.
+ * @ms_drv:		Media specific driver interfaces.
+ * @ma_cap:		Stores MA device info from CapResp packet fields.
+ * @speed:		Stores MA device info from speed capability descriptor.
+ * @pout:		Stores MA device info from P-managed OUT capability
+ *			descriptor.
+ * @iso:		Stores MA device info from isochronous capabilities
+ *			descriptor.
+ * @synch:		Stores MA device info from synchronization capabilities
+ *			descriptor.
+ * @cont_id:		Stores MA device info from container ID capability
+ *			descriptor.
+ * @link_sleep:		Stores MA device info from link sleep capability
+ *			descriptor.
+ */
+struct ma_dev {
+	struct mausb_mgmt		mgmt;
+	struct list_head		dev_list;
+	struct mausb_dev		*top_dev;
+	enum mausb_session_state	session_state;
+	__u8				ma_dev_addr:7;
+	__u8				mass_id;
+	spinlock_t			ma_dev_lock;
+
+	union {
+		struct mausb_hcd *mhcd;
+		struct mausb_udc *maudc;
+	};
+
+	struct mausb_ma_drv		ma_drv;
+	struct mausb_ms_drv		*ms_driver;
+
+	struct ma_capability		ma_cap;
+	struct mausb_dev_cap_speed	*speed;
+	struct mausb_dev_cap_pout	*pout;
+	struct mausb_dev_cap_iso	*iso;
+	struct mausb_dev_cap_sync	*sync;
+	struct mausb_dev_cap_cont_id	*cont_id;
+	struct mausb_dev_cap_link_sleep *link_sleep;
+};
+
+/**
+ * MA USB device data
+ *
+ * This structure is used to hold device-pecific data
+ * (i.e. one instance of this structure exists per usb device).
+ *
+ * @dev:		A pointer to the kernel's usb device structure. Can be
+ *			used to uniquely identify a device.
+ * @gadget:		A pointer to the kernel's usb gadget structure.
+ * @ma_dev:		Pointer to parent ma_dev structure.
+ * @ep_list:		A linked list of all the endpoints for this device.
+ *              	MAUSBDevHandleResp packet.
+ * @dev_handle:		MA USB device handle for this device
+ * @dev_address:	The usb device address. set by the ma_dev.
+ *               	NOTE: this is not the same as the address given by
+ *			the kernel.
+ * @dev_list:		A linked list of all the devices in the HCD.
+ * @dev_lock:		Spinlock for this device. This lock should be held
+ * 			before accessing any data in this structure.
+ */
+struct mausb_dev {
+	union {
+		struct usb_device *dev;	   /* Host only */
+		struct usb_gadget *gadget; /* Device only */
+	};
+	struct ma_dev     *ma_dev;
+	struct list_head   ep_list;
+	__u16              dev_handle;
+	__u8               dev_address;
+	struct list_head   dev_list;
+	spinlock_t         dev_lock;
+};
+
+/**
+ * MAUSB Endpoint Handle State Variables
+ *
+ * Defines the states for an MA USB Endpoint Handle.
+ *
+ * Per MAUSB spec, seciton 7.2
+ *
+ * Note: MAUSB_EP_HANDLE_DELETED is used to flag an endpoint for deletion
+ *       it is not per spec; endpoints in this state should not be used and
+ *       will be deleted in the next EPHandleDeleteReq.
+ */
+enum mausb_ep_handle_state {
+	MAUSB_EP_HANDLE_UNASSIGNED = 0,
+	MAUSB_EP_HANDLE_ACTIVE,
+	MAUSB_EP_HANDLE_INACTIVE,
+	MAUSB_EP_HANDLE_HALTED,
+	MAUSB_EP_HANDLE_DELETED
+};
+
+/**
+ * MA USB host-side endpoint data
+ *
+ * This structure is used to hold endpoint-specific data
+ * (i.e. one instance of this structure exists per endpoint).
+ *
+ * The following data is protected by the devices's dev_lock:
+ *
+ * @ep: 	Used only by the host side. A pointer to the kernel's host-side
+ *      	endpoint structure. Can be used to uniquely identify an
+ *		endpoint. Note: the HCD probably shouldn't read or write
+ *		anything from the usb_host_endpoint structure, since it belongs
+ *		to the kernel.
+ * @dev_ep:	Used only by the device side. A pointer to the kernel's
+ *          	device-side endpoint structure.
+ * @ep_list:	A linked list of all the endpoints connected to the same
+ *           	device.
+ *
+ * The following data is protected by the endpoint's ep_lock:
+ *
+ * @state:		The MA USB state variables for this endpoint. Per
+ *			MA USB Spec, sections 5.4.1 and 5.5.2.
+ * @active_transfer:	Urb that maps to the transfer in progress.
+ * @ep_handle:		The endpoint handle to be used by packets for this
+ *			endpoint per MA USB Spec, section 6.2.1.5.
+ * @ep_handle_state:	Defines the states an Endpoint Handle can be in.
+ *                   	Per MA USB Spec, section 7.2.
+ * @buffer:		Buffer that holds data going to/from a host during
+ *			transfer.
+ * @actual_length:	Length of buffer.
+ * @lman_support:	For control or non-iso OUT endpoints. Indicates if
+ *                	link-managed tranfers are supported. Not valid until
+ *                	an EPHandleResp is received for this endpoint.
+ * @control_dir:	Control endpoints only; used to determine the direction
+ *               	of the current transfer.
+ * @ccu:		The credit conumption unit, in bytes. Per MA USB Spec,
+ *			table 27.
+ * @mausb_dev:		The device the endpoint belongs to.
+ * @urb_list:		A linked list of all URBs pending for this endpoint.
+ *            		URBs map one-to-one with MAUSB Transfers, so each entry
+ *            		also represents an MA USB Transfer.
+ * @usb_req_list:	Only used on the device side. A linked list of all
+ *                	usb_requests submitted to this endpoint.
+ * @req_list:		Head of list of created transferRequests and
+ *	      		transferAck packets.
+ * @resp_list:		Head of list of received transferResponses packets.
+ * @ep_lock:		Spinlock for this endpoint. This lock should be held
+ *			before accessing any data in this structure.
+ * @timer:		Endpoint timer structure, used to monitor transfer
+ *			timeouts.
+ * @timeout_task:	Thread used to perform packet resends after transfer
+ *			timeout.
+ * @host_ep_wq:		Work queue for timeout thread to wait on while sleeping.
+ * @tx_timed_out:	Used to flag when a timeout event has occured during
+ *			a transfer.
+ * @tx_pair:		Transfer pair for this endpoint.
+ * @gadget:		USB gadget associated with this endpoint.
+ * @busy:		True if this endpoint is busy, otherwise false.
+ * @halted:		1 if endpoint is halted, otherwise 0.
+ * @wedged:		1 if endpoint is wedged, otherwise 0.
+ * @stream_en:		1 if streams are enabled for this endpoint, otherwise 0.
+ * @max_pkt:		Max packet size for this endpoint.
+ */
+struct mausb_host_ep {
+
+	struct usb_host_endpoint	*ep; 	 /* Host only */
+	struct usb_ep			*dev_ep; /* Device only */
+	struct list_head		ep_list;
+	struct mausb_ep_state		state;
+	struct mausb_urb		*active_transfer;
+	struct mausb_ep_handle		ep_handle;
+	enum mausb_ep_handle_state	ep_handle_state;
+	void				*buffer;
+	u32				actual_length;
+	bool				lman_support;
+	bool				control_dir;
+	u16				ccu;
+	struct mausb_dev		*mausb_dev;
+	struct list_head		urb_list;
+	struct list_head		*usb_req_list;
+	struct list_head		req_list;
+	struct list_head		resp_list;
+	spinlock_t			ep_lock;
+	struct timer_list		timer;
+	struct task_struct		*timeout_task;
+	wait_queue_head_t		host_ep_wq;
+	bool				tx_timed_out;
+	struct mausb_transfer_pair	tx_pair;
+	struct usb_gadget		*gadget; /* Device only */
+	bool				busy;
+	unsigned			halted:1;
+	unsigned			wedged:1;
+	unsigned			stream_en:1;
+	u16                             max_pkt;
+};
+
+/**
+ * endpoint request structure - describes one I/O request
+ *
+ * @usb_ep:	A device-side endpoint structure.
+ * @queue:	The list of all requests currently enqueued to this endpoint.
+ */
+struct mausb_gadget_ep {
+	struct usb_ep dev_ep;
+	struct list_head usb_req_list;
+};
+
+/**
+ * MA USB urb structure
+ *
+ * Stores MAUSB-specific urb data. In our implementation, one urb from usb
+ * core maps to exactly one MA USB transfer. When an urb is submitted, it
+ * queues a new transfer. When a transfer is complete (or fails), the urb
+ * is given back to the core.
+ *
+ * All data listed in this structure is protected by the ep_lock.
+ * If you want to use any of this data, you need to be in posession
+ * of this lock.
+ *
+ * @urb:		Used only on the host side. The urb submitted to the
+ *			HCD by usbcore.
+ * @usb_request_list:	Used only on the device side. A pointer to the list of
+ *                    	msusb_requests for this endpoint.
+ * @urb_list:		Connects this mausb_urb with other mausb_urbs
+ *			queued to the same endpoint.
+ * @ma_hcd_urb_list:	Connects this urb to urbs queued to the same ma hcd.
+ * @state:		Current state of the transfer as defined in the
+ *			MA USB Spec.
+ * @ep:			The endpoint that the transfer belongs to.
+ * @dev:		The device that the transfer belongs to.
+ * @transfer_size:	Total number of bytes for transfer associated with urb.
+ */
+struct mausb_urb {
+	struct urb			*urb;		   /* Host Only */
+	struct list_head		*usb_request_list; /* Device Only */
+	struct list_head		urb_list;
+	struct list_head		ma_hcd_urb_list;
+	struct mausb_transfer_state	state;
+	struct mausb_host_ep		*ep;
+	struct mausb_dev		*dev;
+	unsigned int			transfer_size;
+};
+
+/**
+ * endpoint request structure - describes one I/O request
+ *
+ * @req:		The usb_request struct. Enqueuing a usb_request is
+ *			what triggers the creation of this struct.
+ * @usb_req_list:	List of all requests enqueued at this endpoint.
+ */
+struct mausb_request {
+	struct usb_request req;
+	struct list_head   usb_req_list;
+};
+
+/* endpoint/device helper functions */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep);
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd);
+
+#define MAUSB_ADD  true
+#define MAUSB_DEL  false
+#define MAUSB_DEV  false
+#define MAUSB_HOST true
+#define MAUSB_OUT  false
+#define MAUSB_IN   true
+struct mausb_pkt *mausb_create_dp(int *status, struct mausb_urb *maurb,
+		bool in, bool host, gfp_t memflags);
+
+/* endpoint/device memory management functions */
+struct mausb_host_ep *mausb_state_to_ep(struct mausb_ep_state *state);
+struct ma_dev *context_to_ma_dev(void *context);
+struct mausb_hcd *mausb_host_ep_to_mahcd(struct mausb_host_ep *ep);
+struct mausb_udc *mausb_host_ep_to_maudc(struct mausb_host_ep *ep);
+struct mausb_dev *usb_dev_to_mausb_dev(struct usb_device *udev);
+struct mausb_host_ep *mausb_find_ep_dev(struct usb_ep *dev_ep,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_host(struct usb_host_endpoint *ep,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_by_handle(struct mausb_ep_handle *handle,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_from_handle(struct mausb_ep_handle handle,
+		struct ma_dev *ma_dev);
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ma_dev(struct ms_pkt *ms_pkt,
+		struct ma_dev *ma_dev, gfp_t mem_flags);
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ep(struct ms_pkt *ms_pkt,
+		struct mausb_host_ep *ep, gfp_t mem_flags);
+struct mausb_dev *mausb_find_dev(struct ma_dev *ma_dev, struct usb_device *dev,
+		unsigned long *handle, struct usb_gadget *gadget);
+struct mausb_dev *mausb_find_dev_host(struct ma_dev *ma_dev,
+		struct usb_device *dev);
+struct mausb_host_ep *mausb_find_ep_by_desc(
+		const struct usb_endpoint_descriptor *ep_desc,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_by_address(u8 address,
+		struct mausb_dev *mausb_dev);
+struct mausb_urb *mausb_alloc_maurb(struct mausb_host_ep *ma_ep,
+		gfp_t memflags);
+int mausb_internal_drop_maurb(struct mausb_urb *maurb, struct mausb_hcd *mhcd);
+void init_ep_state(struct mausb_ep_state *state, u32 buf_size);
+int mausb_activate_endpoints(struct mausb_dev *mausb_dev);
+void mausb_link_ma_ep_to_usb_ep(struct mausb_host_ep *ma_ep,
+		struct usb_ep *dev_ep);
+struct mausb_gadget_ep *usb_ep_to_mausb_gadget_ep(struct usb_ep *ep);
+int mausb_internal_add_ep(struct mausb_dev *ma_dev,
+		struct usb_host_endpoint *ep, struct usb_ep *dev_ep,
+		struct mausb_host_ep **mausb_ep,
+		int (*transfer_timeout)(void *data), gfp_t memflags);
+int mausb_internal_drop_ep(struct mausb_host_ep *ma_ep);
+int mausb_update_ep(struct mausb_host_ep *ma_ep,
+		struct mausb_ep_des *ma_ep_des);
+struct mausb_dev *mausb_internal_alloc_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, struct usb_gadget *gadget);
+int mausb_internal_free_dev(struct ma_dev *ma_dev,
+		struct mausb_dev *mausb_dev);
+int mausb_internal_reset_ma_dev(struct ma_dev *ma_dev, __u8 ma_dev_addr,
+		__u8 mass_id, struct mausb_hcd *mhcd, struct mausb_udc *maudc);
+int mausb_init_ma_device(struct ma_dev *ma_dev, __u8 ma_dev_addr, __u8 mass_id,
+		struct mausb_hcd *mhcd, struct mausb_udc *maudc,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt),
+		int (*device_connect)(int));
+int mausb_init_mgmt(struct mausb_mgmt *mgmt, spinlock_t *ma_dev_lock,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt));
+const struct usb_endpoint_descriptor *mausb_get_ep_des(
+		struct mausb_host_ep *ma_ep);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_state.h b/drivers/staging/mausb/drivers/mausb_state.h
new file mode 100644
index 0000000..01f0171
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_state.h
@@ -0,0 +1,184 @@
+/* Name:	mausb_state.h
+ * Description: Contains all of the state variables for hosts and devices as
+ *              defined by the MAUSB spec.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_STATE_H
+#define __MAUSB_STATE_H
+
+/**
+ * MAUSB endpoint state variables, per MA USB Spec sections 5.4.1 & 5.5.2.
+ *
+ * Note: this struct contains the fields necessary to store the state on both
+ * the host and device side.
+ *
+ * @seq_number:		For a sender, this field contains the sequence number
+ *			that should be placed in the next outgoing packet.
+ *              	For a receiver, this field contains the sequence number
+ *              	expected in the next incoming packet.
+ * @keep_alive_timer:	Timeout counter. Set to aMausbTransferKeepAlive
+ *                    	upon a new transfer initialization. To be decremented
+ *                    	every aMAUSBTransferTimeTick interval. If the timer
+ *                    	reaches 0, A retry is triggered.
+ * @retry_counter: 	Indicates how many more times the
+ *                 	transfer will be attempted. Decremented upon a timeout
+ *                 	(see keep_alive_timer for details). If this counter
+ *                 	reaches 0, the transfer fails due to a timeout.
+ * @request_id: 	Request ID number. for IN transfers,  all
+ *			transfer_request packets currently being sent or
+ *			received should have this request ID number. for OUT
+ *			transfers, All transfer_request and transfer_ack
+ *			packets currently being sent or received should have
+ *			this request ID number.
+ * @active_request_id: 	Active Request ID number. used by IN transfers only.
+ *                     	All transfer_ack packets being sent/received should
+ *                     	contain this number.
+ * @earliest_unacked: 	Stores the sequence number of the most recent packet
+ *                    	that has been sent out but has not been acknowledged
+ *                    	by the receiver.
+ * @rx_buf_size: 	Receiver Buffer Size. Used for OUT transfers only.
+ *			Indicates the available buffer space for packets in the
+ *			device (in bytes).
+ *			Note: this value is signed for the host and
+ *			unsigned for the receiver. A negative number
+ *			indicates a buffer overflow.
+ *			Note: defined in spec as a 25-bit signed int
+ *			for a host and a 32-bit unsigned for a device.
+ * @occupancy: 		Size (in bytes) of the payload accepted into the receive
+ *             		buffer. Used only on the device side for OUT transfers.
+ * @earliest_request_id:Request ID of earliest transferReq whose state
+ *			needs to be tracked (host IN).
+ * @transfer_retries:	Reload value for retry_counter. Should be set to
+ *		      	a ControlTransferRetries, aBulkTransferRetries,
+ *		      	or aInterruptTransferRetries depending on transfer
+ *		      	type.
+ * @delayed:		Set to true if the interval between two sucessive
+ *			transferResp packets exceeds aTransferRepeatTime.
+ * @tx_pending: 	Set to 1 when a transfer is in progress, otherwise it
+ *			should be zero. A new transfer cannot be started until
+ *			this flag is cleared.
+ */
+struct mausb_ep_state {                      /* HOST     | DEVICE       */
+
+	unsigned int seq_number:24;          /* IN | OUT | IN | OUT     */
+	int 	     keep_alive_timer;       /* IN | OUT | IN | OUT     */
+	unsigned int retry_counter;          /* IN | OUT | IN | OUT     */
+	__u8         request_id;             /* IN | OUT | IN | OUT     */
+	__u8         active_request_id;      /* IN | OUT | IN |         */
+	unsigned int earliest_unacked:24;    /*    | OUT | IN | OUT     */
+	__u32        rx_buf_size;            /*    | OUT |    | OUT     */
+	unsigned int occupancy;              /*    |     |    | OUT     */
+	u8	     earliest_request_id;    /* IN | OUT | IN | OUT     */
+	unsigned int transfer_retries;       /* IN | OUT | IN | OUT     */
+	bool	     delayed;                /*    |     | IN |         */
+
+	/* TODO: add response_timer (device IN and OUT/host OUT) */
+
+	unsigned int tx_pending:1;       /* beyond spec */
+};
+
+/**
+ * MA USB transfer state variables, per section 5.4.1 & 5.5.2.
+ *
+ * In our implementation, URBs and MAUSB transfers map one-to-one,
+ * so the transfer state and the urb state are one in the same.
+ *
+ * @rem_size:		The remaining transfer size (in bytes). This value is
+ *			set at the beginning of a transfer and is decremented
+ *			as data is received.
+ * @payload_size:	Payload size for out transfer (in bytes). For MA USB
+ *			host, it indicates the overall transfered OUT payload
+ *			size for the current urb. For MA USB device, It
+ *			indicates the received OUT payload size for the
+ *			current MA USB OUT request.
+ * @transfer_error:	A boolean which is only set to TRUE when a
+ *			non-recoverable error is detected in the transfer.
+ * @transfer_complete: 	A boolean which is only set to TRUE when a transfer
+ *                     	is evaluated to be complete. (ie. the final ACK has
+ *                     	has been sent/received).
+ * @eot_detected: 	A boolean which is only set to TRUE when a transfer
+ *                	is complete (ie: all the data has been transferred).
+ *                	Note: eot_detected & transfer_complete differ in when
+ *                	they are set. eot_detected is sent after the last data
+ *                	packet received, transfer_complete is set after the
+ *			final ACK.
+ * @last_transfer_sn: 	Last Transfer Sequence Number. Stores the sequence
+ *                    	number of the final packet of this transfer.
+ * @transfer_acked:	Set to true when a transferReq or transferAck packet is
+ *                  	released to the data channel acknowledging the last
+ *		    	transferResp belonging to a transfer.
+ * @k:			A  transfer-dependent multiplicative factor used to
+ *			reload keep_alive_timer when a transfer has a status
+ *			of TRANSFER_PENDING.
+ * @ack_transfer_sn:	The value of the sequence number in the last
+ *                   	transferReq packet that belongs to the transfer and
+ *                   	has the ARQ field set to 1.
+ */
+struct mausb_transfer_state {             /* HOST     | DEVICE       */
+
+	__u32        rem_size;            /* IN | OUT | IN | OUT     */
+	__u32        payload_size;        /* IN | OUT | IN | OUT     */
+	bool         transfer_error;      /* IN | OUT | IN | OUT     */
+	bool         transfer_complete;   /* IN | OUT | IN | OUT     */
+	bool         eot_detected;        /* IN |     | IN | OUT     */
+	unsigned int last_transfer_sn:24; /* IN |     | IN |         */
+	bool         transfer_acked;      /* IN | OUT |    |         */
+	unsigned int k;                   /* IN |     |    |         */
+	unsigned int ack_transfer_sn:24;  /*    | OUT |    |         */
+
+	/*TODO: add transfer_completion_timer (host IN) */
+};
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 04/10] added media agnostic (MA) USB packet handling
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (2 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we handle MA USB packets. The structure and types of MA USB
packets are defined in the MA USB specification. When an MA USB driver
receives a USB packet, it translates it into a MA USB packet (or packets
if urb exceeds maximum USB packet size). When an MA USB packet is received,
the data from that packet is given to the waiting USB packet and the USB
packet is released.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_pkt.c | 1038 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_pkt.h |  914 +++++++++++++++++++++++++
 2 files changed, 1952 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.h

diff --git a/drivers/staging/mausb/drivers/mausb_pkt.c b/drivers/staging/mausb/drivers/mausb_pkt.c
new file mode 100644
index 0000000..c78cfc2
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_pkt.c
@@ -0,0 +1,1038 @@
+/* name:	mausb_pkt.c
+ * description: MA USB packet helper functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb.h>
+
+#include "mausb_mem.h"
+#include "mausb_pkt.h"
+#include "mausb_const.h"
+
+/**
+ * Translates numerical packet type into corresponding string (for printing).
+ */
+const char *mausb_type_to_string(enum mausb_pkt_type type)
+{
+	switch (type) {
+	case CapReq:
+		return "CapReq";
+	case CapResp:
+		return "CapResp";
+	case USBDevHandleReq:
+		return "USBDevHandleReq";
+	case USBDevHandleResp:
+		return "USBDevHandleResp";
+	case EPHandleReq:
+		return "EPHandleReq";
+	case EPHandleResp:
+		return "EPHandleResp";
+	case EPActivateReq:
+		return "EPActivateReq";
+	case EPActivateResp:
+		return "EPActivateResp";
+	case EPInactivateReq:
+		return "EPInactivateReq";
+	case EPInactivateResp:
+		return "EPInactivateResp";
+	case EPResetReq:
+		return "EPResetReq";
+	case EPResetResp:
+		return "EPResetResp";
+	case EPClearTransferReq:
+		return "EPClearTransferReq";
+	case EPClearTransferResp:
+		return "EPClearTransferResp";
+	case EPHandleDeleteReq:
+		return "EPHandleDeleteReq";
+	case EPHandleDeleteResp:
+		return "EPHandleDeleteResp";
+	case DevResetReq:
+		return "DevResetReq";
+	case DevResetResp:
+		return "DevResetResp";
+	case ModifyEP0Req:
+		return "ModifyEP0Req";
+	case ModifyEP0Resp:
+		return "ModifyEP0Resp";
+	case SetUSBDevAddrReq:
+		return "SetUSBDevAddrReq";
+	case SetUSBDevAddrResp:
+		return "SetUSBDevAddrResp";
+	case UpdateDevReq:
+		return "UpdateDevReq";
+	case UpdateDevResp:
+		return "UpdateDevResp";
+	case USBDevDisconnectReq:
+		return "USBDevDisconnectReq";
+	case USBDevDisconnectResp:
+		return "USBDevDisconnectResp";
+	case USBSuspendReq:
+		return "USBSuspendReq";
+	case USBSuspendResp:
+		return "USBSuspendResp";
+	case USBResumeReq:
+		return "USBResumeReq";
+	case USBResumeResp:
+		return "USBResumeResp";
+	case RemoteWakeReq:
+		return "RemoteWakeReq";
+	case RemoteWakeResp:
+		return "RemoteWakeResp";
+	case PingReq:
+		return "PingReq";
+	case PingResp:
+		return "PingResp";
+	case DevDisconnectReq:
+		return "DevDisconnectReq";
+	case DevDisconnectResp:
+		return "DevDisconnectResp";
+	case DevInitDisconnectReq:
+		return "DevInitDisconnectReq";
+	case DevInitDisconnectResp:
+		return "DevInitDisconnectResp";
+	case SyncReq:
+		return "SyncReq";
+	case SyncResp:
+		return "SyncResp";
+	case CancelTransferReq:
+		return "CancelTransferReq";
+	case CancelTransferResp:
+		return "CancelTransferResp";
+	case EPOpenStreamReq:
+		return "EPOpenStreamReq";
+	case EPOpenStreamResp:
+		return "EPOpenStreamResp";
+	case EPCloseStreamReq:
+		return "EPCloseStreamReq";
+	case EPCloseStreamResp:
+		return "EPCloseStreamResp";
+	case USBDevResetReq:
+		return "USBDevResetReq";
+	case USBDevResetResp:
+		return "USBDevResetResp";
+	case DevNotificationReq:
+		return "DevNotificationReq";
+	case DevNotificationResp:
+		return "DevNotificationResp";
+	case EPSetKeepAliveReq:
+		return "EPSetKeepAliveReq";
+	case EPSetKeepAliveResp:
+		return "EPSetKeepAliveResp";
+	case GetPortBWReq:
+		return "GetPortBWReq";
+	case GetPortBWResp:
+		return "GetPortBWResp";
+	case SleepReq:
+		return "SleepReq";
+	case SleepResp:
+		return "SleepResp";
+	case WakeReq:
+		return "WakeReq";
+	case WakeResp:
+		return "WakeResp";
+	case VendorSpecificReq:
+		return "VendorSpecificReq";
+	case VendorSpecificResp:
+		return "VendorSpecificResp";
+	case TransferSetupReq:
+		return "TransferSetupReq";
+	case TransferSetupResp:
+		return "TransferSetupResp";
+	case TransferTearDownConf:
+		return "TransferTearDownConf";
+	case TransferReq:
+		return "TransferReq";
+	case TransferResp:
+		return "TransferResp";
+	case TransferAck:
+		return "TransferAck";
+	case IsochTransferReq:
+		return "IsochTransferReq";
+	case IsochTransferResp:
+		return "IsochTransferResp";
+	}
+
+	return "unknown";
+}
+EXPORT_SYMBOL(mausb_type_to_string);
+
+/**
+ * Translates a negative errno to a MAUSB status. Returns a packet status value.
+ */
+enum mausb_pkt_status mausb_errno_to_ma_status(int errno)
+{
+	switch (errno) {
+	case 0: /* no error */
+		return SUCCESS;
+	case -EINPROGRESS:
+		return TRANSFER_PENDING;
+	case -ESTRPIPE:
+		return TRANSFER_EP_STALL;
+	/* TODO: map all relevant ma status' */
+	default:
+		return UNSUCCESSFUL;
+	} /* end switch */
+
+}
+EXPORT_SYMBOL(mausb_errno_to_ma_status);
+
+/**
+ * Translates an URB status to a MAUSB status
+ */
+int mausb_to_urb_status(enum mausb_pkt_status pkt_status)
+{
+	switch (pkt_status) {
+	case SUCCESS: /* no error */
+		return 0;
+	case TRANSFER_PENDING:
+		return -EINPROGRESS;
+	case TRANSFER_EP_STALL:
+		return -ESTRPIPE;
+	/* TODO: map all relevant urb statuses */
+	default:
+		return -EIO; /* generic I/O error */
+	} /* end switch */
+
+}
+EXPORT_SYMBOL(mausb_to_urb_status);
+
+/**
+ * Determines if the packet is a response packet. Returns true if the packet is
+ * a response packet. Returns false otherwise.
+ */
+bool mausb_pkt_resp(struct mausb_pkt *pkt)
+{
+	return pkt->common->pkt_type & MAUSB_PKT_RESP_FLAG;
+}
+
+/**
+ * Determines if a given packet is a management packet.
+ */
+static bool mausb_pkt_is_mgmt(struct mausb_pkt_common *common)
+{
+	if ((common->pkt_type & MAUSB_PKT_TYPE_MASK) == MAUSB_PKT_TYPE_MGMT)
+		return true;
+	else
+		return false;
+}
+
+
+/**
+ * Returns the sum of the sequnce number & the value added. Handles sequence
+ * number wraparound.
+ */
+u32 mausb_seq_num_add(u32 seq_num, int val)
+{
+	return (seq_num + val) % (MAUSB_MAX_SEQ_NUM + 1);
+}
+EXPORT_SYMBOL(mausb_seq_num_add);
+
+/**
+ * Increments a sequence number value by one.
+ */
+void mausb_increment_seq_num(u32 *seq_num)
+{
+	*seq_num = mausb_seq_num_add(*seq_num, 1);
+}
+
+/**
+ * Compares two sequence numbers. Returns true if a is less than b.
+ * Handles sequence number wraparound.
+ */
+bool mausb_seq_num_lt(u32 a, u32 b)
+{
+
+	if (a > MAUSB_MAX_SEQ_NUM || b > MAUSB_MAX_SEQ_NUM) {
+		mapkt_warn("%s: input out of range\n", __func__);
+		return false;
+	}
+
+	if (b < MAUSB_HALF_SEQ_NUM) { /* b is in the lower half */
+
+		if ((b > a) || ((b + MAUSB_HALF_SEQ_NUM) < a))
+			return true;
+		else
+			return false;
+
+	} else { /* b is in the upper half */
+
+		if ((b > a) && (b - MAUSB_HALF_SEQ_NUM) < a)
+			return true;
+		else
+			return false;
+	}
+
+	/* we should never get here */
+	BUG();
+	return false;
+}
+EXPORT_SYMBOL(mausb_seq_num_lt);
+
+/**
+ * Sequence number less than or equal to.
+ */
+bool mausb_seq_num_lt_eq(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(b, a) ? false : true;
+}
+
+/**
+ * Sequence number greater than or equal to.
+ */
+bool mausb_seq_num_gt_eq(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(a, b) ? false : true;
+}
+
+/**
+ * Sequence number greater than.
+ */
+bool mausb_seq_num_gt(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(b, a);
+}
+EXPORT_SYMBOL(mausb_seq_num_gt);
+
+/**
+ * Returns the sum of the request id and the value added. Handles request id
+ * wraparound.
+ */
+u8 mausb_req_id_add(u8 req_id, int val)
+{
+	return (req_id + val) % (MAUSB_MAX_REQ_ID + 1);
+}
+EXPORT_SYMBOL(mausb_req_id_add);
+
+/**
+ * Compares 2 request IDs. Returns true if a is less than b. Handles request id
+ * wraparound.
+ */
+bool mausb_req_id_lt(u8 a, u8 b)
+{
+
+	if (a > MAUSB_MAX_REQ_ID || b > MAUSB_MAX_REQ_ID) {
+		mapkt_warn("%s: input out of range\n", __func__);
+		return false;
+	}
+
+	if (b < MAUSB_HALF_REQ_ID) { /* b is in the lower half */
+
+		if ((b > a) || ((b + MAUSB_HALF_REQ_ID) < a))
+			return true;
+		else
+			return false;
+
+	} else { /* b is in the upper half */
+
+		if ((b > a) && (b - MAUSB_HALF_REQ_ID) < a)
+			return true;
+		else
+			return false;
+	}
+
+	/* we should never get here */
+	BUG();
+	return false;
+}
+EXPORT_SYMBOL(mausb_req_id_lt);
+
+bool mausb_req_id_gt(u8 a, u8 b)
+{
+	return mausb_req_id_lt(b, a);
+}
+
+bool mausb_req_id_gt_eq(u8 a, u8 b)
+{
+	return mausb_req_id_lt(a, b) ? false : true;
+}
+EXPORT_SYMBOL(mausb_req_id_gt_eq);
+
+/**
+ * Finds an endpoint descriptor inside of an endpoint handle request
+ */
+struct usb_endpoint_descriptor *mausb_ep_handle_req_get_ep_des(
+	struct mausb_EPHandleReq_flds *req, int i)
+{
+
+	if (i >= le32_to_cpu(req->num_ep_des)) {
+		mapkt_warn("%s: endpoint descriptor not in packet\n", __func__);
+		return NULL;
+	}
+
+	if (MAUSB_EP_REQ_SIZE == le32_to_cpu(req->size_ep_des)) {
+		return (struct usb_endpoint_descriptor *)
+					&req->ep_des[i].ep_des;
+
+	} else if (MAUSB_SS_EP_REQ_SIZE == le32_to_cpu(req->size_ep_des)) {
+		return (struct usb_endpoint_descriptor *)
+					 &req->ss_ep_des[i].ep_des;
+
+	} else {
+		mapkt_err("%s: unsupported size_ep_des value (%u)\n",
+			  __func__, le32_to_cpu(req->size_ep_des));
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(mausb_ep_handle_req_get_ep_des);
+
+static struct mausb_pkt_common *mausb_header_from_ms_pkt(struct ms_pkt *pkt)
+{
+	struct mausb_pkt_common *header;
+
+	if (pkt->kvec[0].iov_len < sizeof(*header)) {
+		mapkt_err("%s: first entry too small for header\n", __func__);
+		header = NULL;
+	} else
+		header = pkt->kvec[0].iov_base;
+
+	return header;
+}
+
+/**
+ * Accepts an MA USB packet for the MA device and forwards it to the correct
+ * handler based on packet type and endpoint/device handle.
+ */
+int mausb_pkt_dmux(struct ms_pkt *pkt, void *context)
+{
+	int				ret = -EINVAL;
+	struct mausb_pkt_common		*header = mausb_header_from_ms_pkt(pkt);
+	struct ma_dev			*ma_dev = context_to_ma_dev(context);
+	struct mausb_host_ep		*ma_ep = NULL;
+	struct mausb_pkt_transfer	*transfer = NULL;
+
+	if (mausb_pkt_is_mgmt(header)) {
+		transfer = &ma_dev->mgmt.tx_pair.to_ma;
+
+	} else {
+		/* otherwise, find the endpoint it belongs to */
+		ma_ep = mausb_find_ep_from_handle(header->ep_handle,
+			ma_dev);
+
+		if (NULL != ma_ep)
+			transfer = &ma_ep->tx_pair.to_ma;
+	}
+
+	if (NULL != transfer)
+		ret = transfer->transfer_packet(pkt, transfer->context);
+
+	return ret;
+}
+
+/**
+ * Packet destructor for packets generated by the MA driver. For packets that we
+ * have created, we want to free the header but not the data buffers (since the
+ * buffers belong to the URB).
+ */
+static void mausb_pkt_destructor(struct ms_pkt *ms_pkt)
+{
+	struct mausb_pkt *ma_pkt = ms_pkt_to_mausb_pkt(ms_pkt);
+
+	kfree(ma_pkt->common);
+
+	return;
+}
+
+/**
+ * Allocates space for given packet type.
+ */
+struct mausb_pkt *mausb_alloc_pkt(enum mausb_pkt_type pkt_type, int *status,
+		gfp_t memflags)
+{
+	int			size;
+	int			ret = 0;
+	struct mausb_pkt	*pkt;
+
+	/* determine header length */
+	switch (pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	case MAUSB_PKT_TYPE_MGMT:
+		size = sizeof(struct mausb_mgmt_pkt);
+		break;
+	case MAUSB_PKT_TYPE_CTRL:
+		size = sizeof(struct mausb_ctrl_pkt);
+		break;
+	case MAUSB_PKT_TYPE_DATA:
+		size = sizeof(struct mausb_iso_dph);
+		break;
+	default:
+		mapkt_err("%s: could not determine packet type\n", __func__);
+		if (NULL != status)
+			*status = -EINVAL;
+		return NULL;
+	}
+
+	pkt = kzalloc(sizeof(struct mausb_pkt), memflags);
+	if (NULL == pkt) {
+		ret = -ENOMEM;
+		pkt = NULL;
+	} else {
+		pkt->common = kzalloc(size, memflags);
+		if (NULL == pkt->common) {
+			mapkt_err("could not allocate memory for MA USB"
+				" packet header of length %i\n", size);
+			kfree(pkt);
+			ret = -ENOMEM;
+			pkt = NULL;
+		}
+
+		pkt->ms_pkt_destructor = &mausb_pkt_destructor;
+		pkt->orig_pkt = &pkt->pkt;
+	}
+
+	if (NULL != status)
+		*status = ret;
+
+	return pkt;
+}
+
+/**
+ * Deletes the given data packet
+ */
+void mausb_free_pkt(struct mausb_pkt *pkt)
+{
+	/* kill the buffers (when necessary) */
+	pkt->ms_pkt_destructor(pkt->orig_pkt);
+	kfree(pkt);
+}
+EXPORT_SYMBOL(mausb_free_pkt);
+
+/**
+ * Returns the length of the header or a negative errno.
+ */
+int mausb_pkt_header_length(struct mausb_pkt_common *header)
+{
+	int length;
+
+	switch (header->pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	case MAUSB_PKT_TYPE_MGMT:
+	case MAUSB_PKT_TYPE_CTRL:
+		length = le16_to_cpu(header->length);
+		break;
+	case MAUSB_PKT_TYPE_DATA:
+		length = sizeof(struct mausb_dph);
+		break;
+	default:
+		mapkt_err("%s:invalid packet type\n", __func__);
+		length = -EINVAL;
+		break;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(mausb_pkt_header_length);
+
+/**
+ * Returns a pointer to a buffer of specified length that is
+ * found offset a given number of bytes into the ms_pkt.
+ *
+ * If a contigious buffer can be found, this function returns
+ * the virtual address of this buffer. otherwise, it returns null
+ */
+static void *mausb_get_buf_from_ms_pkt(struct ms_pkt *pkt,
+		int offset, int buf_length)
+{
+	int		i;
+	int		page_offset = offset;
+	char		*ret = NULL;
+	struct kvec	*current_kvec;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_kvec = &pkt->kvec[i];
+
+		/* if the buffer is in this kvec entry */
+		if (page_offset < current_kvec->iov_len) {
+
+			/* and the whole buffer is in current_kvec */
+			if (page_offset + buf_length <= current_kvec->iov_len) {
+				ret = (char *) current_kvec->iov_base;
+				ret += page_offset;
+			}
+
+			return ret;
+		}
+
+		page_offset -= current_kvec->iov_len;
+	}
+
+	if (0 != page_offset) {
+		mapkt_err("%s: offset of %i Bytes is greater than packet"
+			" length\n", __func__, page_offset);
+	}
+	return NULL;
+}
+
+bool mausb_pkt_has_setup_data(struct mausb_dph *header)
+{
+	/*
+	 * Only control transfer requests with sequence number 0 should have
+	 * setup data - nothing else should ever carry setup data.
+	 */
+	if (header->common.pkt_type == TransferReq) {
+		if ((header->eps_tflags & MAUSB_PKT_TFLAG_TYPE_MASK)
+			== MAUSB_PKT_TFLAG_TYPE_CTRL
+			&& le32_to_cpu(header->seq_num) == 0)
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(mausb_pkt_has_setup_data);
+
+/**
+ * Gets an mausb_pkt structure from a given ms_pkt structure.
+ *
+ * can only be used if this driver created the packet i.e. if you just received
+ * an ms_pkt from another machine, it will not be part of a mausb_pkt.
+ */
+struct mausb_pkt *ms_pkt_to_mausb_pkt(struct ms_pkt *ms_pkt)
+{
+	return container_of(ms_pkt, struct mausb_pkt, pkt);
+}
+
+/**
+ * Creates a mausb_pkt structure from a given ms_pkt structure. Used for parsing
+ * incoming packets.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt(struct ms_pkt *ms_pkt,
+	void (*ms_pkt_destructor)(struct ms_pkt *ms_pkt), gfp_t mem_flags)
+{
+	struct mausb_pkt	*pkt;
+	int			current_offset;
+	int			packet_length;
+
+	pkt = kzalloc(sizeof(struct mausb_pkt), mem_flags);
+	if (NULL == pkt)
+		return NULL;
+
+	pkt->pkt = *ms_pkt;
+	pkt->orig_pkt = ms_pkt;
+	pkt->ms_pkt_destructor = ms_pkt_destructor;
+
+	/* the first portion is always the header */
+	pkt->common = mausb_header_from_ms_pkt(ms_pkt);
+	current_offset = mausb_pkt_header_length(pkt->common);
+	packet_length = pkt->common->length;
+
+	/* checks to see if header is contigious */
+	if (NULL == mausb_get_buf_from_ms_pkt(ms_pkt, 0, current_offset)) {
+
+		mapkt_err("%s: packet header bigger than entry (header is %i"
+			" bytes)\n", __func__, current_offset);
+		kfree(pkt);
+		return NULL;
+	}
+
+	/*
+	 * NOTE: Currently control and management packets must be contigious.
+	 *       data packet headers must also be contigious.
+	 *       (ie: the data must all be in 1 ms_pkt entry).
+	 *
+	 * TODO: handle when a control/management is in more than 1
+	 *       kvec entry
+	 */
+
+	if (MAUSB_PKT_TYPE_DATA ==
+		(pkt->common->pkt_type & MAUSB_PKT_TYPE_MASK)) {
+
+		if (mausb_pkt_has_setup_data(pkt->data)) {
+			pkt->setup = mausb_get_buf_from_ms_pkt(ms_pkt,
+				current_offset, sizeof(*pkt->setup));
+
+			if (NULL == pkt->setup) {
+				mapkt_err("%s: could not get setup data\n",
+					__func__);
+			} else {
+				current_offset += sizeof(*pkt->setup);
+			}
+		}
+
+		if (packet_length > current_offset) {
+			pkt->buffer = mausb_get_buf_from_ms_pkt(ms_pkt,
+				current_offset, packet_length - current_offset);
+
+			/*
+			 * if the remaining data was contigious, treat it as a
+			 * buffer
+			 */
+			if (NULL != pkt->buffer) {
+				pkt->buffer_length =
+					packet_length - current_offset;
+				current_offset += pkt->buffer_length;
+			}
+
+		} else if (packet_length < current_offset) {
+			mapkt_dbg("%s: packet_length:%i, current_offset:%i\n",
+				__func__, packet_length, current_offset);
+		}
+	}
+
+	/* checks to see if there is data after packet */
+	if (NULL != mausb_get_buf_from_ms_pkt(ms_pkt, current_offset, 0))
+		mapkt_warn("%s: Warning: data exists after packet\n", __func__);
+
+	return pkt;
+
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt);
+
+/**
+ * Fills the ms_pkt of a given mausb_pkt based on fields in the mausb_pkt struct.
+ */
+int mausb_pkt_fill_ms_pkt(struct mausb_pkt *pkt, gfp_t mem_flags)
+{
+	struct ms_pkt		*ms_pkt = &pkt->pkt;
+	unsigned int		ent_length;
+
+	ms_pkt->nents = 0;
+
+	if (NULL != pkt->common) {
+		/* add the header */
+		ent_length = mausb_pkt_header_length(pkt->common);
+		if (0 >= ent_length) {
+			return -EINVAL;
+		}
+
+	} else { /* We should ALWAYS have a header, and we dont... */
+		mapkt_err("%s: header not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->common;
+	ms_pkt->kvec[ms_pkt->nents].iov_len = ent_length;
+	ms_pkt->nents += 1;
+
+	/* If this packet should have data, send it */
+	if (pkt->common->pkt_type == TransferReq ||
+		pkt->common->pkt_type == TransferResp){
+
+		/* add the setup field */
+		if (mausb_pkt_has_setup_data(pkt->data)) {
+			ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->setup;
+			ms_pkt->kvec[ms_pkt->nents].iov_len =
+						sizeof(*pkt->setup);
+			ms_pkt->nents += 1;
+
+		} else if (NULL != pkt->setup) {
+			mapkt_warn("%s: Warning: packet has Setup field, but "
+				"flags in header are not set\n", __func__);
+		}
+
+		if (NULL != pkt->buffer && pkt->nents > 0) {
+			mapkt_err("%s: packet has scatterlist and databuffer\n"
+				, __func__);
+			return -EINVAL;
+		}
+
+		/* add the data buffer */
+		if (NULL != pkt->buffer) {
+			ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->buffer;
+			ms_pkt->kvec[ms_pkt->nents].iov_len =
+				pkt->buffer_length;
+			ms_pkt->nents += 1;
+		}
+	}
+
+	mapkt_dbg("%s: pkt filled with %i entries\n", __func__, ms_pkt->nents);
+
+	return 0;
+}
+
+/**
+ * Calculates the total length of data contained in an ms_pkt (in bytes).
+ * Returns the length of the kvec, or 0 on an error.
+ */
+static int mausb_ms_data_length(struct ms_pkt *pkt)
+{
+	int		i;
+	int		total_length;
+	struct kvec	*current_kvec;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_kvec = &pkt->kvec[i];
+		if (NULL == current_kvec)
+			return -EINVAL;
+		else
+			total_length += current_kvec->iov_len;
+	}
+
+	return total_length;
+}
+
+/**
+ * Calculates the length of the datafield in a given datapacket.
+ */
+static int mausb_pkt_datafield_length(struct mausb_pkt *pkt)
+{
+	int length = 0;
+
+	if (NULL != pkt->buffer)
+		length += pkt->buffer_length;
+	if (0 != pkt->nents)
+		length += mausb_ms_data_length(&pkt->pkt);
+
+	return length;
+}
+
+/**
+ * Parses the packet fields to determine how long the packet is. Returns the
+ * packet length on sucess, or a negative errno on error.
+ */
+int mausb_pkt_length(struct mausb_pkt *pkt)
+{
+	int length;
+
+	/* all packets have this field */
+	switch (pkt->common->pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	/* Management packets */
+	case MAUSB_PKT_TYPE_MGMT:
+		length = sizeof(*pkt->common);
+		length += MAUSB_MGMT_TOKEN_PAD_LEN;
+
+		/* subtypes without additional data */
+		switch (pkt->common->pkt_type) {
+		case DevResetReq:
+		case DevResetResp:
+		case UpdateDevResp:
+		case DevDisconnectReq:
+		case DevDisconnectResp:
+		case USBDevDisconnectReq:
+		case USBDevDisconnectResp:
+		case SleepReq:
+		case SleepResp:
+		case WakeReq:
+		case WakeResp:
+		case RemoteWakeReq:
+		case RemoteWakeResp:
+		case PingReq:
+		case PingResp:
+		case DevInitDisconnectReq:
+		case DevInitDisconnectResp:
+		case SyncResp:
+			break;
+
+		/* subtypes with constant length additional data */
+		case CapReq:
+			length += sizeof(pkt->mgmt->cap_req);
+			break;
+		case CapResp:
+			length += sizeof(pkt->mgmt->cap_resp);
+			/* also include length of any descriptors */
+			length += pkt->mgmt->cap_resp.desc_length;
+			break;
+		case USBDevHandleReq:
+			length += sizeof(pkt->mgmt->usb_dev_handle_req);
+			break;
+		case USBDevHandleResp:
+			length += sizeof(pkt->mgmt->usb_dev_handle_resp);
+			break;
+		case ModifyEP0Req:
+			length += sizeof(pkt->mgmt->modify_ep0_req);
+			break;
+		case ModifyEP0Resp:
+			length += sizeof(pkt->mgmt->modify_ep0_resp);
+			break;
+		case SetUSBDevAddrReq:
+			length += sizeof(pkt->mgmt->set_dev_addr_req);
+			break;
+		case SetUSBDevAddrResp:
+			length += sizeof(pkt->mgmt->set_dev_addr_resp);
+			break;
+		case UpdateDevReq:
+			length += sizeof(pkt->mgmt->update_dev_req);
+			break;
+		case SyncReq:
+			length += sizeof(pkt->mgmt->synch_req);
+			break;
+		case EPCloseStreamReq:
+			length += sizeof(pkt->mgmt->ep_close_stream_req);
+			break;
+		case CancelTransferReq:
+			length += sizeof(pkt->mgmt->cancel_transfer_req);
+			break;
+		case CancelTransferResp:
+			length += sizeof(pkt->mgmt->cancel_transfer_resp);
+			break;
+		case EPOpenStreamReq:
+			length += sizeof(pkt->mgmt->ep_open_stream_req);
+			break;
+		/* subtypes with variable length additional data */
+		case EPHandleReq:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_req.num_ep_des *
+				pkt->mgmt->ep_handle_req.size_ep_des;
+			break;
+		case EPHandleResp:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_resp.num_ep_des *
+				sizeof(struct mausb_ep_des);
+			break;
+		case EPActivateReq:
+		case EPActivateResp:
+		case EPInactivateReq:
+		case EPInactivateResp:
+		case EPResetReq:
+		case EPResetResp:
+		case EPClearTransferReq:
+		case EPClearTransferResp:
+		case EPHandleDeleteReq: /* FALLTHROUGH */
+		case EPHandleDeleteResp:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_delete.num_ep
+				* sizeof(struct mausb_ep_handle);
+			break;
+		case EPCloseStreamResp:
+		case USBDevResetReq:
+		case USBDevResetResp:
+		case EPOpenStreamResp:
+		case VendorSpecificReq:
+		case VendorSpecificResp:
+			mapkt_err("%s: cannot determine length of %s packet -"
+				" packet type not yet handled\n", __func__,
+				mausb_type_to_string(pkt->common->pkt_type));
+			BUG();
+			break;
+		default:
+			mapkt_err("%s: invalid management packet type %x\n",
+				__func__, pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+
+		break;
+
+	/* Control Packets */
+	case MAUSB_PKT_TYPE_CTRL:
+		length = sizeof(struct mausb_ctrl_pkt);
+		switch (pkt->common->pkt_type) {
+		case TransferSetupReq:
+			length += sizeof(struct mausb_TransferSetupReq_flds);
+			break;
+		case TransferSetupResp:
+			break;
+		case TransferTearDownConf:
+			break;
+		default:
+			mapkt_err("%s: invalid control packet type %x\n",
+				__func__, pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+		break;
+
+	/* Data Packets */
+	case MAUSB_PKT_TYPE_DATA:
+
+		length = sizeof(struct mausb_dph);
+
+		switch (pkt->common->pkt_type) {
+		case TransferReq:
+		case TransferResp: /* FALLTHROUGH */
+			if (mausb_pkt_has_setup_data(pkt->data))
+				length += sizeof(*pkt->setup);
+
+			length += mausb_pkt_datafield_length(pkt);
+			break;
+		case TransferAck:
+			break;
+		case IsochTransferReq:
+		case IsochTransferResp: /* FALLTHROUGH */
+			length = sizeof(struct mausb_iso_dph);
+			length += mausb_pkt_datafield_length(pkt);
+
+			break;
+		default:
+			mapkt_err("%s: invalid data packet type %x\n", __func__,
+				pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+		break;
+
+	default:
+		mapkt_err("%s: invalid packet type %x\n", __func__,
+			pkt->common->pkt_type);
+		BUG();
+		break;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(mausb_pkt_length);
+
+/**
+ * Finds and returns the memory location offset a number of bytes from a
+ * CapResp packet. Used to find or place device capability descriptors in
+ * a CapResp packet.
+ */
+struct mausb_dev_cap_desc *cap_desc_ptr_increment(struct mausb_mgmt_pkt *resp,
+						  int offset)
+{
+	struct mausb_dev_cap_desc *desc;
+	char  *temp;
+
+	temp = (char *) resp;
+	temp += offset;
+
+	desc  =  (struct mausb_dev_cap_desc *) (temp);
+
+	return desc;
+}
+EXPORT_SYMBOL(cap_desc_ptr_increment);
+
diff --git a/drivers/staging/mausb/drivers/mausb_pkt.h b/drivers/staging/mausb/drivers/mausb_pkt.h
new file mode 100644
index 0000000..fe959c7
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_pkt.h
@@ -0,0 +1,914 @@
+/* name:	mausb_pkt.h
+ * description:	library of MA USB packet structures
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_PKT_H__
+#define __MAUSB_PKT_H__
+
+#include <linux/usb/ch9.h>
+#include "mausb_msapi.h"
+
+#ifdef DEBUG
+#define mapkt_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mapkt_dbg(format, arg...)
+#endif
+
+#define mapkt_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mapkt_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* protocol Version, per section 6.2.1.1 */
+#define MAUSB_VERSION_1_0     0x0
+#define MAUSB_VERSION_MASK    0x0F
+
+/* packet Flags, per section 6.2.1.2 */
+#define MAUSB_PKT_FLAG_MASK       0xF0
+#define MAUSB_PKT_FLAG_HOST       (1 << 4)
+#define MAUSB_PKT_FLAG_RETRY      (1 << 5)
+#define MAUSB_PKT_FLAG_TIMESTAMP  (1 << 6)
+
+/* packet Types, per section 6.2.1.3 */
+#define MAUSB_PKT_TYPE_MASK       0xC0
+#define MAUSB_PKT_TYPE_MGMT       (0 << 6)
+#define MAUSB_PKT_TYPE_CTRL       (1 << 6)
+#define MAUSB_PKT_TYPE_DATA       (2 << 6)
+
+/* packet Subtypes, section 6.2.1.3 */
+#define MAUSB_SUBTYPE_MASK        0x3F
+
+enum mausb_pkt_type {
+	/* Management packets */
+	CapReq = 0x00 | MAUSB_PKT_TYPE_MGMT,
+	CapResp               , /* 1 */
+	USBDevHandleReq       , /* 2 */
+	USBDevHandleResp      , /* 3 */
+
+	EPHandleReq           , /* 4 */
+	EPHandleResp          , /* 5 */
+	EPActivateReq         , /* 6 */
+	EPActivateResp        , /* 7 */
+	EPInactivateReq       , /* 8 */
+	EPInactivateResp      , /* 9 */
+	EPResetReq            , /* 10 */
+	EPResetResp           , /* 11 */
+	EPClearTransferReq    , /* 12 */
+	EPClearTransferResp   , /* 13 */
+	EPHandleDeleteReq     , /* 14 */
+	EPHandleDeleteResp    , /* 15 */
+
+	DevResetReq           , /* 16 */
+	DevResetResp          , /* 17 */
+	ModifyEP0Req          , /* 18 */
+	ModifyEP0Resp         , /* 19 */
+	SetUSBDevAddrReq      , /* 20 */
+	SetUSBDevAddrResp     , /* 21 */
+	UpdateDevReq          , /* 22 */
+	UpdateDevResp         , /* 23 */
+	USBDevDisconnectReq   , /* 24 */
+	USBDevDisconnectResp  , /* 25 */
+
+	USBSuspendReq         , /* 26 */
+	USBSuspendResp        , /* 27 */
+	USBResumeReq          , /* 28 */
+	USBResumeResp         , /* 29 */
+	RemoteWakeReq         , /* 30 */
+	RemoteWakeResp        , /* 31 */
+	PingReq               , /* 32 */
+	PingResp              , /* 33 */
+	DevDisconnectReq      , /* 34 */
+	DevDisconnectResp     , /* 35 */
+	DevInitDisconnectReq  , /* 36 */
+	DevInitDisconnectResp , /* 37 */
+	SyncReq               , /* 38 */
+	SyncResp              , /* 39 */
+	CancelTransferReq     , /* 40 */
+	CancelTransferResp    , /* 41 */
+	EPOpenStreamReq       , /* 42 */
+	EPOpenStreamResp      , /* 43 */
+	EPCloseStreamReq      , /* 44 */
+	EPCloseStreamResp     , /* 45 */
+	USBDevResetReq        , /* 46 */
+	USBDevResetResp       , /* 47 */
+
+	DevNotificationReq    , /* 48 */
+	DevNotificationResp   , /* 49 */
+	EPSetKeepAliveReq     , /* 50 */
+	EPSetKeepAliveResp    , /* 51 */
+	GetPortBWReq          , /* 52 */
+	GetPortBWResp         , /* 53 */
+	SleepReq              , /* 54 */
+	SleepResp             , /* 55 */
+	WakeReq               , /* 56 */
+	WakeResp              , /* 57 */
+
+	/* Vendor-Specific Management Packets */
+	VendorSpecificReq = 0x3E | MAUSB_PKT_TYPE_MGMT,
+	VendorSpecificResp    ,
+
+	/* Control Packets */
+	TransferSetupReq = 0x00 | MAUSB_PKT_TYPE_CTRL,
+	TransferSetupResp     ,
+	TransferTearDownConf  ,
+
+	/* Data Packets */
+	TransferReq = 0x00 | MAUSB_PKT_TYPE_DATA,
+	TransferResp = 0x01 | MAUSB_PKT_TYPE_DATA,
+	TransferAck           ,
+	IsochTransferReq      ,
+	IsochTransferResp
+};
+
+/* Endpoint Handle Fields, per section 6.2.1.5 */
+struct __packed mausb_ep_handle {
+	union {
+		struct {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+			__le16 dir:1;      /**< Direction Field    */
+			__le16 ep_num:4;   /**< Endpoint Number    */
+			__le16 dev_addr:7; /**< USB Device Address */
+			__le16 bus_num:4;  /**< Bus Number         */
+#else
+			__le16 bus_num:4;  /**< Bus Number         */
+			__le16 dev_addr:7; /**< USB Device Address */
+			__le16 ep_num:4;   /**< Endpoint Number    */
+			__le16 dir:1;      /**< Direction Field    */
+#endif
+		};
+		__u16 handle;
+	};
+};
+
+#define MAUSB_VIRTUAL_BUS_NUM 15
+
+/* The least significant bit of the packet is only set to 1 in */
+/* response packets. */
+#define MAUSB_PKT_RESP_FLAG       0x01
+
+/** Status Code Values, per section 6.2.1.8, Table 6 */
+enum mausb_pkt_status {
+	SUCCESS = 0,
+	UNSUCCESSFUL = 128,
+	INVALID_MA_USB_SESSION_STATE,
+	INVALID_DEVICE_HANDLE,
+	INVALID_EP_HANDLE,
+	INVALID_EP_HANDLE_STATE,
+	INVALID_REQUEST,
+	MISSING_SEQUENCE_NUMBER,
+	TRANSFER_PENDING,
+	TRANSFER_EP_STALL,
+	TRANSFER_SIZE_ERROR,
+	TRANSFER_DATA_BUFFER_ERROR,
+	TRANSFER_BABBLE_DETECTED,
+	TRANSFER_TRANSACTION_ERROR,
+	TRANSFER_SHORT_TRANSFER,
+	TRANSFER_CANCELLED,
+	INSUFFICENT_RESOURCES,
+	NOT_SUFFICENT_BANDWIDTH,
+	INTERNAL_ERROR,
+	DATA_OVERRUN,
+	DEVICE_NOT_ACCESSED,
+	BUFFER_OVERRUN,
+	BUSY,
+	DROPPED_PACKET,
+	ISOC_TIME_EXPIRED,
+	ISOCH_TIME_INVALID,
+	NO_USB_PING_RESPONSE,
+	NOT_SUPPORTED,
+	REQUEST_DENIED
+};
+
+/* Status codes NO_ERROR and SUCCESS are interchangeable. */
+#define NO_ERROR SUCCESS
+
+/* MA USB packet header size, per 6.2.1 */
+#define MAUSB_PKT_HEADER_SIZE	12
+
+/** common header fields, per section 6.2.1 */
+struct __packed mausb_pkt_common {
+	/* DWORD 0 */
+	__u8                  ver_flags;   /**< MA USB version & Flags */
+	enum mausb_pkt_type   pkt_type:8;  /**< type and subtype */
+	__le16                 length;     /**< length (in bytes) */
+	/* DWORD 1 */
+	union {
+		struct mausb_ep_handle ep_handle; /**< Endpoint Handle */
+		__le16                  dev_handle;/**< Device Handle */
+	};
+	__u8                  ma_dev_addr;/**< MA USB Device Address */
+	__u8                  mass_id;    /**< MA USB Service Set (MSS) id*/
+	/* DWORD 2 */
+	enum mausb_pkt_status pkt_status:8; /**< packet status code */
+};
+
+/** MA USB Global Time, per section 6.6.1 */
+struct __packed mausb_time {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	/** value of delta field in ITP, defined in USB 3.1 spec. */
+	__le32 delta:13;
+	/** nominal bus interval, Indicates USB microframe number */
+	__le32 nom_bus_itvl:19;
+#else
+	__le32 nom_bus_itvl:19;
+	__le32 delta:13;
+#endif
+};
+
+#define MAUSB_PKT_WSE_NO_DOCK  0
+#define MAUSB_PKT_WSE_DOCK_2_0 1
+#define MAUSB_PKT_WSE_DOCK_3_0 2
+
+/**
+ * MAUSB Device Functionality Support Speed
+ *
+ * mausb_dev_bfs_speed are used for the bFunctionalitySupport field.
+ * Note that they are different values than usb_device_speed.
+ */
+enum mausb_dev_bfs_speed {
+	MAUSB_LOW_SPEED = 0,
+	MAUSB_FULL_SPEED,
+	MAUSB_HIGH_SPEED,
+	MAUSB_SUPER_SPEED,
+	MAUSB_SUPER_SPEED_PLUS,
+	MAUSB_INVALID_SPEED
+};
+
+/* MA USB Capability Request fields, per 6.3.2, table 7 */
+struct __packed mausb_CapReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 max_mgmt_reqs:12; /**< max # of outstanding mgmt reqs to host */
+	__le32 rsvd:20; /**< reserved */
+#else
+	__le32 rsvd:20; /**< reserved */
+	__le32 max_mgmt_reqs:12; /**< max # of outstanding mgmt reqs to host */
+#endif
+};
+
+#define MAUSB_DEV_TYPE_INTEGRATED 0
+#define MAUSB_DEV_TYPE_HS_HUB 1
+#define MAUSB_DEV_TYPE_SS_HUB 2
+
+/** MA USB Capability Response fields, per 6.3.3, table 12 */
+struct __packed mausb_CapResp_flds {
+	__le16 num_ep;       	/**< number of endpoints */
+	__u8  num_dev;      	/**< number of devices */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__u8  num_stream:5; /**< 2^this value = max streams supported */
+	__u8  dev_type:3;   /**< 0 = not a hub, 1 = 2.0 hub, 2 = 3.1 hub */
+#else
+	__u8  dev_type:3;   /**< 0 = not a hub, 1 = 2.0 hub, 2 = 3.1 hub */
+	__u8  num_stream:5; /**< 2^this value = max streams supported */
+#endif
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 desc_count:8;    /**< descriptors count */
+	__le32 desc_length:24;  /**< total length of descriptors */
+#else
+	__le32 desc_length:24;  /**< total length of descriptors */
+	__le32 desc_count:8;    /**< descriptors count */
+#endif
+
+	__le16 max_tx_reqs;     /**< max # of outstanding transfer reqs */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 max_mgmt_reqs:12;/**< max # of outstanding management reqs */
+	__le16 rsvd:4;          /**< reserved */
+#else
+	__le16 rsvd:4;          /**< reserved */
+	__le16 max_mgmt_reqs:12;/**< max # of outstanding management reqs */
+#endif
+};
+
+/** MA USB Device Capability Type Values, per 6.3.3, table 14 */
+enum mausb_dev_cap_type {
+	MAUSB_DEV_CAP_SPEED = 0,
+	MAUSB_DEV_CAP_POUT,
+	MAUSB_DEV_CAP_ISO,
+	MAUSB_DEV_CAP_SYNC,
+	MAUSB_DEV_CAP_CONT_ID,
+	MAUSB_DEV_CAP_LINK_SLEEP
+};
+
+/** Speed Capability Speed Enumeration, per 6.3.3.1 */
+enum mausb_dev_cap_speed_speed {
+	MAUSB_DEV_CAP_SPEED_LOW = 0,
+	MAUSB_DEV_CAP_SPEED_FULL,
+	MAUSB_DEV_CAP_SPEED_HIGH,
+	MAUSB_DEV_CAP_SPEED_SUPER,
+	MAUSB_DEV_CAP_SPEED_SS_PLUS
+};
+
+/** Speed Capability Descriptor, per 6.3.3.1 */
+struct __packed mausb_dev_cap_speed {
+	/* DWORD n+0 */
+	__u8 rsvd_0:4;                          /**< Reserved */
+	enum mausb_dev_cap_speed_speed speed:4; /**< USB Device Speed */
+	__u8 rsvd_1:4;                          /**< Reserved */
+	__u8 lse:2;                             /**< Lane Speed Exponent */
+	__u8 st:2;                              /**< Sublink Type */
+
+	/* DWORD n+1 */
+	__u8  rsvd_2:2;			/**< Reserved */
+	__u8  lane_count:4;		/**< Lane Count */
+	__u8  link_protocol:2;		/**< Link Protocol */
+	__le16 lsm;			/**< Lane Speed Mantissa */
+};
+
+#define MAUSB_DEV_CAP_SPEED_LENGTH 7
+
+/** P-Managed OUT Capabilities Descriptor, per 6.3.3.2 */
+struct __packed mausb_dev_cap_pout {
+	__u8 elastic_buf_cap:1;		/**< Elastic Buffer Capability */
+	__u8 drop_notif:1;		/**< Drop Notification */
+	__u8 rsvd:6;			/**< Reserved */
+
+};
+
+#define MAUSB_DEV_CAP_POUT_LENGTH 3
+
+/** Isochronous Capabilities Descriptor, per 6.3.3.3 */
+struct __packed mausb_dev_cap_iso {
+	__u8 iso_alignment:1;	/**< Isochronous Payload Alignment */
+	__u8 rsvd:7;		/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_ISO_LENGTH 3
+
+/** Synchronization Capabilities Descriptor, per 6.3.3.4 */
+struct __packed mausb_dev_cap_sync {
+	__u8 media_time_avail:1;	/**< Media Time Available */
+	__u8 timestamp_req:1;		/**< Timestamp Request */
+	__u8 rsvd:6;			/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_SYNCH_LENGTH 3
+
+/** Container ID Capability Descriptor, per 6.3.3.5 */
+struct __packed mausb_dev_cap_cont_id {
+	long long int cont_id_upper;	/**< 64 msb of Container ID */
+	long long int cont_id_lower;	/**< 64 lsb of Container ID */
+};
+
+#define MAUSB_DEV_CAP_CONT_ID_LENGTH 18
+
+/** Link Sleeo Capability Descriptor, per 6.3.3.6 */
+struct __packed mausb_dev_cap_link_sleep {
+	__u8 link_sleep_cap:1;		/**< Link Sleep Capable */
+	__u8 rsvd:7;			/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_LINK_SLEEP_LENGTH 3
+
+/** MA Device Capability Descriptor  */
+struct __packed mausb_dev_cap_desc {
+	/* common descriptor fields */
+	__u8 length;				/**< Descriptor length */
+	enum mausb_dev_cap_type cap_type:8;     /**< Capability type */
+
+	/* Descriptor-specific format */
+	union {
+		struct mausb_dev_cap_speed      speed;
+		struct mausb_dev_cap_pout       pout;
+		struct mausb_dev_cap_iso        iso;
+		struct mausb_dev_cap_sync       sync;
+		struct mausb_dev_cap_cont_id    cont_id;
+		struct mausb_dev_cap_link_sleep link_sleep;
+	};
+};
+
+/** USB Device Handle Request fields, per 6.3.4, table 8 */
+struct __packed mausb_USBDevHandleReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 usb_rt_str:20;     /**< USB Route String, per USB3.0 Spec */
+	__le32 speed:4;           /**< USB Device Speed */
+	__le32 rsvd_0:8;          /**< reserved */
+	__le16 dock_hub;          /**< dock hub device handle */
+	__le16 rsvd_1;            /**< reserved */
+	__le16 parent_hub;        /**< parent hub handle (if LS or HS) */
+	__u8  parent_hub_port:4;  /**< parent hub port   (if LS or HS) */
+	__u8  mtt:1;              /**< multiple transaction translators */
+	__le16 rsvd_2:15;         /**< reserved */
+	__u8  lse:2;		  /**< lane speed exponent */
+	__u8  st:2;		  /**< sublink type */
+	__u8  rsvd_3:2;		  /**< reserved */
+	__u8  lane_count:2;	  /**< lane count */
+	__u8  link_protocol:2;	  /**< link protocol */
+	__le16 lsm;		  /**< lane speed mantissa */
+
+#else
+	__le16 lsm;		  /**< lane speed mantissa */
+	__u8  link_protocol:2;	  /**< link protocol */
+	__u8  lane_count:2;	  /**< lane count */
+	__u8  rsvd_3:2;		  /**< reserved */
+	__u8  st:2;		  /**< sublink type */
+	__u8  lse:2;		  /**< lane speed exponent */
+	__le16 rsvd_2:15;         /**< reserved */
+	__u8  mtt:1;              /**< multiple transaction translators */
+	__u8  parent_hub_port:4;  /**< parent hub port   (if LS or HS) */
+	__le16 parent_hub;        /**< parent hub handle (if LS or HS) */
+	__le16 rsvd_1;            /**< reserved */
+	__le16 dock_hub;          /**< dock hub device handle */
+	__le32 rsvd_0:8;          /**< reserved */
+	__le32 speed:4;           /**< USB Device Speed */
+	__le32 usb_rt_str:20;     /**< USB Route String, per USB3.0 Spec */
+#endif
+};
+
+/* maximum number of EPs in a packet array */
+#define MAUSB_PKT_MAX_NUM_EP 31
+
+/* EPHandleReq constants, per section 6.3.6 */
+#define MAUSB_EP_REQ_SIZE 8
+#define MAUSB_EP_REQ_PADDING (MAUSB_EP_REQ_SIZE - USB_DT_ENDPOINT_SIZE)
+#define MAUSB_SS_EP_REQ_SIZE 16
+#define MAUSB_SS_EP_REQ_PADDING (MAUSB_SS_EP_REQ_SIZE - \
+		(USB_DT_ENDPOINT_SIZE + USB_DT_SS_EP_COMP_SIZE))
+
+/** packed USB endpoint descriptor */
+struct __packed mausb_ep_req {
+	unsigned char ep_des[USB_DT_ENDPOINT_SIZE];
+	unsigned char padding[MAUSB_EP_REQ_PADDING];
+};
+
+/** packed SuperSpeed USB endpoint descriptor */
+struct __packed mausb_ss_ep_req {
+	unsigned char ep_des[USB_DT_ENDPOINT_SIZE];
+	unsigned char ss_ep_comp_des[USB_DT_SS_EP_COMP_SIZE];
+	unsigned char padding[MAUSB_SS_EP_REQ_PADDING];
+};
+
+/** Endpoint Handle Request fields, per 6.3.6, Tables 10 & 11 */
+struct __packed mausb_EPHandleReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep_des:5;  /**< number of EP descriptors in the packet */
+	__le32 size_ep_des:6; /**< size of EP descriptors (in bytes) */
+	__le32 rsvd:21;        /**< reserved */
+#else
+	__le32 rsvd:21;
+	__le32 size_ep_des:6;
+	__le32 num_ep_des:5;
+#endif
+	/** array of endpoint descriptors (Standard or SuperSpeed) */
+	union {
+		struct mausb_ep_req ep_des[MAUSB_PKT_MAX_NUM_EP]
+			__aligned(4);
+		struct mausb_ss_ep_req ss_ep_des[MAUSB_PKT_MAX_NUM_EP]
+			__aligned(4);
+		/* TODO: structure for USB 3.1 devices with ISO endpoints */
+	};
+};
+
+
+/** WEP Descriptor format, per 6.3.7, table 13 */
+struct __packed mausb_ep_des {
+	struct mausb_ep_handle ep_handle; /**< requested endpoint handle */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 dir:1;        /**< direction */
+	__le16 iso:1;        /**< isochronous */
+	__le16 l_man:1;      /**< L-managed transfers */
+	__le16 valid:1;      /**< valid handle bit */
+	__le16 rsvd_0:12;    /**< reserved */
+#else
+	__le16 rsvd_0:12;    /**< reserved */
+	__le16 valid:1;      /**< valid handle bit */
+	__le16 l_man:1;      /**< L-managed transfers */
+	__le16 iso:1;        /**< isochronous */
+	__le16 dir:1;        /**< direction */
+#endif
+	__le16 ccu;          /**< credit consumption unit */
+	__le16 rsvd_1;       /**< reserved */
+	__le32 buffer_size;  /**< buffer size (in bytes) */
+	__le16 iso_prog_dly; /**< max iso programming delay (in uSec) */
+	__le16 iso_resp_dly; /**< max iso response delay (in uSec) */
+};
+
+/** Endpoint Handle Response fields, per 6.3.7, Tables 12 & 13 */
+struct __packed mausb_EPHandleResp_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep_des:5; /**< number of EP descriptors in this packet */
+	__le32 rsvd:27;      /**< reserved */
+#else
+	__le32 rsvd:27;      /**< reserved */
+	__le32 num_ep_des:5; /**< number of EP descriptors in this packet */
+#endif
+	struct mausb_ep_des ep_des[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Endpoint Handle Delete fields, per 6.3.16 & 6.3.17, Tables 37 & 38 */
+/*
+ * Note: both the request and response packets are in the same format.
+ * The the request contains all the handles to delete, and the
+ * response indicates how many were deleted.
+ */
+struct __packed mausb_EPHandleDelete_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep:5; /**< number of EP descriptors */
+	__le32 rsvd:27;  /**< reserved */
+#else
+	__le32 rsvd:27;  /**< reserved */
+	__le32 num_ep:5; /**< number of EP descriptors */
+#endif
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Modify EP0 Request and Response fields, per 6.3.20-21, table 39 & 40 */
+struct __packed mausb_ModifyEP0_flds {
+	/** Endpoint 0 handle for the device */
+	struct mausb_ep_handle ep_handle;
+	union {
+		__le16 max_pkt_size; /**< Maximum packet size for EP0 */
+		__le16 rsvd; 	     /**< reserved */
+	};
+};
+
+/** Set USB Device Address Request fields, per 6.3.22, table 41 */
+struct __packed mausb_SetDevAddrReq_flds {
+	__le16  resp_timeout; /**< time the device has to respond (in ms) */
+	__le16  rsvd;
+};
+
+/** Set USB Device Address Response fields, per 6.3.23, table 42 */
+struct __packed mausb_SetDevAddrResp_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32  dev_addr:7; /**< USB Device Address from request */
+	__le32  rsvd:25;
+#else
+	__le32  rsvd:25;
+	__le32  dev_addr:7; /**< USB Device Address from request */
+#endif
+};
+
+/** Update Device Request fields, per 6.3.24, Table 28 */
+struct __packed mausb_UpdateDevReq_flds {
+	__le16 max_exit_lat; /**< Max Exit Latency */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__u8  hub:1;        /**< Hub flag, set to 1 if hub */
+	__u8  num_ports:4;  /**< hub only, number of downward-facing ports */
+	__u8  mtt:1;        /**< HS hub only, Multiple Transaction Translator */
+	__u8  ttt:2;        /**< HS hub only, Transaction Think Time */
+	/**< 0 = at most 8  FS bit times */
+	/**< 1 = at most 16 FS bit times */
+	/**< 2 = at most 24 FS bit times */
+	/**< 3 = at most 32 FS bit times */
+#else
+	__u8  ttt:2;
+	__u8  mtt:1;
+	__u8  num_ports:4;
+	__u8  hub:1;
+#endif
+};
+
+/** MAUSB Synchronization Request fields, per 6.3.40, Table 30 */
+struct __packed mausb_SynchReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16             td_valid:1; /**< Transmission Delay field valid */
+	__le16             rsvd:15;    /**< reserved */
+#else
+	__le16             rsvd:15;    /**< reserved */
+	__le16             td_valid:1; /**< Transmission Delay field valid */
+#endif
+	struct mausb_time timestamp;   /**< MA USB Timestamp, per 6.5.1.11 */
+	__le32             tx_dly;     /**< Transmission delay, per 6.5.1.12 */
+};
+
+/** Cancel Transfer Request fields, per 6.3.42, Table 31 */
+struct __packed mausb_CancelTransferReq_flds {
+	struct mausb_ep_handle ep_handle;	/**< Target Endpoint Handle */
+	__le16                  stream_id;	/**< Target stream ID */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32                  req_id:8;	/**< Target request ID */
+	__le32                  rsvd:24;	/**< reserved */
+#else
+	__u32                  rsvd:24;    /**< reserved */
+	__u32                  req_id:8;    /**< Target request ID */
+#endif
+};
+
+/** Cancel Transfer Response fields, per 6.3.43, Table 32 */
+struct __packed mausb_CancelTransferResp_flds {
+	struct mausb_ep_handle ep_handle;
+	__u16 stream_id;
+	/** Cancellation status                         */
+	/** 0 = Cancel Error                            */
+	/** 1 = Cancel Sucess before any data was moved */
+	/** 2 = Cancel Sucess after some data was moved */
+	/** 3 = Transfer not found                      */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 req_id:8;
+	__le32 cancel_status:2;
+	__le32 rsvd_0:22;
+#else
+	__le32 rsvd_0:22;
+	__le32 cancel_status:2;
+	__le32 req_id:8;
+#endif
+	/** Delivered Sequence Number */
+	/** For OUT Transfers only. Only valid if cancel_status = 2 */
+	/** Indicates last sequence number delivered to the device. */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 deliv_seq_num:24;
+	__le32 rsvd_1:8;
+#else
+	__le32 deliv_seq_num:24;
+	__le32 rsvd_1:8;
+#endif
+	/** Delivered Byte Offset. Only valid if cancel_status = 2 */
+	__le32 deliv_byte_offset;
+};
+
+/** Enpoint Open Stream Request fields, per 6.3.44, Table 33 */
+struct __packed mausb_EPOpenStreamReq_flds {
+	struct mausb_ep_handle ep_handle; /**< Target bulk endpoint */
+	__le32  num_streams:17; /**< number of streams to be opened */
+	__le32  rsvd:7;
+};
+
+/** Enpoint Inactivate Request fields, per 6.3.10, Table 30 */
+struct __packed mausb_EPInactivateReq_flds {
+	__u8  num_ep_handles:5; /** number of ep handles included packet */
+	__u8  suspend_flg:1; /** indicates if issued due to suspension of */
+			     /** included endpoints */
+			     /** 0 = endpoints not suspended */
+			     /** 1 = endpoints suspended */
+	__u32  rsvd:26;
+
+	/** list of EP handles MA USB host is requesting to inactivate */
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Enpoint Inactivate Response fields, per 6.3.11, Table 33 */
+struct __packed mausb_EPInactivateResp_flds {
+	__u8  num_ep_with_error:5; /** number of EP handles with */
+				   /** unsuccessful inactivation */
+				   /** should only be non-zero if */
+				   /** packet status is not SUCCESS */
+	__u32  rsvd:27;
+
+	/** list of EP handles whose inactivation failed */
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+#define MAUSB_MGMT_MAX_TOKEN ((1 << 10) - 1)
+#define MAUSB_MGMT_TOKEN_PAD_LEN 3 /* token + pad to DWORD */
+
+/** Management Packet fields, per 6.3.1 */
+struct __packed mausb_mgmt_pkt {
+	struct mausb_pkt_common common;
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16                  token:10;
+	__le16                  padding:6; /* for DWORD alignment */
+#else
+	__le16                  padding:6; /* for DWORD alignment */
+	__le16                  token:10;
+#endif
+	__u8                    padding_2;
+	union {
+		struct mausb_CapReq_flds             cap_req;
+		struct mausb_CapResp_flds            cap_resp;
+		struct mausb_USBDevHandleReq_flds    usb_dev_handle_req;
+		__le16                                usb_dev_handle_resp;
+		struct mausb_EPHandleReq_flds        ep_handle_req;
+		struct mausb_EPHandleResp_flds       ep_handle_resp;
+		struct mausb_EPHandleDelete_flds     ep_handle_delete;
+		struct mausb_ModifyEP0_flds          modify_ep0_req;
+		struct mausb_ModifyEP0_flds          modify_ep0_resp;
+		struct mausb_SetDevAddrReq_flds      set_dev_addr_req;
+		struct mausb_SetDevAddrResp_flds     set_dev_addr_resp;
+		struct mausb_UpdateDevReq_flds       update_dev_req;
+		struct mausb_SynchReq_flds           synch_req;
+		__le16                                ep_close_stream_req;
+		struct mausb_CancelTransferReq_flds  cancel_transfer_req;
+		struct mausb_CancelTransferResp_flds cancel_transfer_resp;
+		struct mausb_EPOpenStreamReq_flds    ep_open_stream_req;
+		struct mausb_EPInactivateReq_flds    ep_inactivate_req;
+		struct mausb_EPInactivateResp_flds   ep_inactivate_resp;
+
+		/* TODO: add remaining management packet data */
+
+	};
+};
+
+/** Transfer Setup Request fields, per 6.4.1, Table 38 */
+struct __packed mausb_TransferSetupReq_flds {
+	/** Identifies link type     */
+	/** 0     = Reserved         */
+	/** 1     = IEEE 802.11 link */
+	/** 2-255 = Reserved         */
+	__u8 link_type;
+	/** Connection ID data is dependant on Link Type */
+	union {
+		/** for 802.11 links (link_type == 1) */
+		struct __packed {
+			__u8 tid:4;  /**< Traffic Identifier */
+			__u8 rsvd:4;
+		} connection_id;
+	};
+};
+
+/** Control Packet fields, per 6.4 */
+struct __packed mausb_ctrl_pkt {
+	struct mausb_pkt_common common;
+	struct mausb_TransferSetupReq_flds transfer_setup_req;
+	__u8 padding; /* for header DWORD alignment */
+};
+
+#define MAUSB_PKT_EPS_UNASSIGNED 0
+#define MAUSB_PKT_EPS_ACTIVE     1
+#define MAUSB_PKT_EPS_INACTIVE   2
+#define MAUSB_PKT_EPS_HALTED     3
+
+#define MAUSB_PKT_TFLAG_ARQ  (1 << 2)
+#define MAUSB_PKT_TFLAG_NEG  (1 << 3)
+#define MAUSB_PKT_TFLAG_EOT  (1 << 4)
+#define MAUSB_PKT_TFLAG_TYPE_CTRL (0 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_ISOC (1 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_BULK (2 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_INT  (3 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_MASK 0x60
+
+#define MAUSB_PKT_SEQ_NUM_MASK 0x00FFFFFF
+
+/** Fields common to all datapackets, per 6.5 */
+struct __packed mausb_dph {
+	struct mausb_pkt_common common;
+	__u8   eps_tflags;	/**< EPS & T-Flags */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 num_seg:12;
+	__le16 iflags:4;
+#else
+	__le16 iflags:4;
+	__le16 num_seg:12;
+#endif
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 seq_num:24;	/**< Sequence Number */
+	__le32  req_id:8;	/**< request ID */
+#else
+	__le32  req_id:8;	/**< request ID */
+	__le32 seq_num:24;      /**< Sequence Number */
+#endif
+	union {
+		__le32 remaining_size_credit;
+		__le32 present_time;
+	};
+};
+
+/** Fields exclusive to isochronous data packets, per 6.5 */
+struct __packed mausb_iso_dph {
+	struct mausb_dph data;
+	__le32 wse_ts;          /**< WSE Timestamp */
+	__le32 tx_dly;          /**< Transmission Delay */
+};
+
+
+/* unless the urb contains scattergather buffers, a packet will
+ * need at most 3 entries:
+ *	- 1 for the header
+ *	- 1 for the setup data
+ *	- 1 for the data buffer
+ *
+ */
+#define MAUSB_MS_PKT_ORIG_NENTS 4
+
+/**
+ * mausb_pkt structure
+ *
+ * Can be used to parse any type of MAUSB packet, regardless of contents.
+ * If the packet type is known, this structure shouldn't be used. Instead,
+ * a type-specific structure (ie: mausb_XXXX_pkt) should be used.
+ *
+ * @setup:		setup data (control packets only)
+ * @buffer:		data buffer
+ * @buffer_length:	length of data buffer
+ * @pkt_list:		connects packet to other packets in a linked list
+ * @kvec_list:		kvec list
+ * @nents:		number of kvecs
+ * @pkt:		A compilation of all the buffers needed to be sent
+ *			across the medium. Used to pass packet to medium.
+ * @orig_pkt:		Original ms_pkt for this packet. Used for destructor.
+ *	 		If this packet originated from the MA driver, it will
+ *			point to the ms_pkt of this ma_pkt. If it came in from
+ *			the MS driver, it will point at the ms_pkt it sent
+ *			us. This is used by the ms_pkt_destructor, so we can
+ *			make sure we are pointing to the right ms_pkt.
+ */
+struct mausb_pkt {
+	union {
+		struct mausb_pkt_common *common;
+		struct mausb_mgmt_pkt   *mgmt;
+		struct mausb_ctrl_pkt   *ctrl;
+		struct mausb_dph        *data;
+		struct mausb_iso_dph    *iso_data;
+	};
+
+	struct usb_ctrlrequest *setup;
+	void *buffer;
+	u32 buffer_length;
+	struct list_head pkt_list;
+	struct kvec *kvec_list;
+	int nents;
+	struct ms_pkt pkt;
+	struct ms_pkt *orig_pkt;
+	void (*ms_pkt_destructor)(struct ms_pkt *pkt);
+};
+
+enum mausb_pkt_buf_copy_dir {
+	MAUSB_PKT_BUF_COPY_TO_KVEC = 0,
+	MAUSB_PKT_BUF_COPY_FROM_KVEC
+};
+
+void mausb_pkt_buf_copy_kvec(struct mausb_pkt *pkt, int buf_length, int offset,
+			  struct kvec *kv, int nents,
+			   enum mausb_pkt_buf_copy_dir dir);
+
+/* function declarations */
+const char *mausb_type_to_string(enum mausb_pkt_type type);
+int mausb_pkt_fill_ms_pkt(struct mausb_pkt *pkt, gfp_t mem_flags);
+int mausb_pkt_header_length(struct mausb_pkt_common *header);
+enum mausb_pkt_status mausb_errno_to_ma_status(int errno);
+int mausb_to_urb_status(enum mausb_pkt_status pkt_status);
+struct usb_endpoint_descriptor *mausb_ep_handle_req_get_ep_des(
+		struct mausb_EPHandleReq_flds *req, int i);
+int mausb_pkt_length(struct mausb_pkt *pkt);
+struct mausb_pkt *mausb_alloc_pkt(enum mausb_pkt_type pkt_type, int *status,
+		gfp_t memflags);
+int mausb_generate_ms_pkt(struct mausb_pkt *pkt);
+bool mausb_pkt_has_setup_data(struct mausb_dph *header);
+struct mausb_pkt *ms_pkt_to_mausb_pkt(struct ms_pkt *ms_pkt);
+struct mausb_pkt *mausb_pkt_from_ms_pkt(struct ms_pkt *ms_pkt,
+		void (*ms_pkt_destructor)(struct ms_pkt *ms_pkt),
+		gfp_t mem_flags);
+int mausb_pkt_dmux(struct ms_pkt *ms_pkt, void *context);
+void mausb_free_pkt(struct mausb_pkt *pkt);
+bool mausb_pkt_resp(struct mausb_pkt *pkt);
+struct mausb_dev_cap_desc *cap_desc_ptr_increment(struct mausb_mgmt_pkt *resp,
+		int offset);
+
+/* Helper functions for sequence number and request id wraparound */
+u32 mausb_seq_num_add(u32 seq_num, int val);
+void mausb_increment_seq_num(u32 *seq_num);
+bool mausb_seq_num_lt(u32 a, u32 b);
+bool mausb_seq_num_lt_eq(u32 a, u32 b);
+bool mausb_seq_num_gt_eq(u32 a, u32 b);
+bool mausb_seq_num_gt(u32 a, u32 b);
+u8 mausb_req_id_add(u8 req_id, int val);
+bool mausb_req_id_lt(u8 a, u8 b);
+bool mausb_req_id_gt(u8 a, u8 b);
+bool mausb_req_id_gt_eq(u8 a, u8 b);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (3 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-04  8:48     ` Tobias Klauser
  2014-11-03 20:42   ` [PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
                     ` (5 subsequent siblings)
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we handle media specific packets and transport. The MS driver
interfaces with a media agnostic (MA) driver via a series of transfer pairs.
Transfer pairs consist of a set of functions to pass MA USB packets back
and forth between MA and MS drivers. There is one transfer pair per device
endpoint and one transfer pair for control/management traffic. When the MA
driver needs to send an MA USB packet, it hands the packet off to the MS
layer where the packet is converted into an MS form and sent via TCP over
the underlying ethernet or wireless medium. When the MS driver receives a
packet, it converts it into an MA USB packet and hands it off the the MA
driver for handling.

In addition, the MS driver provides an interface to inititate connection events.
Because there are no physical MA USB ports in an MA USB host, the host must be
notified via software when a device is connected.

Lastly, the MS driver contains a number of ioctl functions that are used by a
utility to adjust medium-related driver parameters and connect or disconnect the
MA USB host and device drivers.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_ioctl.c      | 373 +++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_ioctl.h      |  99 +++++
 drivers/staging/mausb/drivers/mausb_msapi.c      | 110 ++++++
 drivers/staging/mausb/drivers/mausb_msapi.h      | 232 ++++++++++++
 drivers/staging/mausb/drivers/mausb_tcp-device.c | 147 ++++++++
 drivers/staging/mausb/drivers/mausb_tcp-host.c   | 144 ++++++++
 drivers/staging/mausb/drivers/mausb_tcp.c        | 446 +++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tcp.h        | 129 +++++++
 8 files changed, 1680 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h

diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.c b/drivers/staging/mausb/drivers/mausb_ioctl.c
new file mode 100644
index 0000000..0c6c6bd
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_ioctl.c
@@ -0,0 +1,373 @@
+/* Name:         mausb_ioctl.c
+ * Description:  ioctl functions for MA USB media specific driver
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/usb/gadget.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include "mausb_hcd.h"
+#include "mausb_udc.h"
+#include "mausb_ioctl.h"
+
+/* #define MAUSB_PRINT_IOCTL_MAGIC */
+
+static int ma_open;
+static char message[BUFFER];
+static char *message_point;
+
+/**
+ * This function is used to send a message to the user, in other words, the
+ * calling process. It basically copies the message one byte at a time.
+ *
+ * @msg:	The message to be sent to the user.
+ * @buffer:	The buffer in which to put the message. This buffer was given to
+ *	    	us to fill.
+ */
+void to_user(char *msg, long unsigned int buffer)
+{
+	int length = (int)strlen(msg);
+	int bytes = 0;
+
+	while (length && *msg) {
+		put_user(*(msg++), (char *)buffer++);
+		length--;
+		bytes++;
+	}
+
+	put_user('\0', (char *)buffer + bytes);
+}
+
+/**
+ * This function is used to open the device file in order to read/write
+ * from/to it.
+ *
+ * @inode:	Struct with various information that is passed in when this
+ *		function is called. We don't need to use it for our purposes.
+ * @file:	The file to be opened.
+ */
+static int mausb_open(struct inode *inode, struct file *file)
+{
+	if (ma_open)
+		return -EBUSY;
+	ma_open++;
+	message_point = message;
+	try_module_get(THIS_MODULE);
+
+	return 0;
+}
+
+/**
+ * This function is used to close the device file.
+ *
+ * @inode:	Struct with various information that is passed in when this
+ *		function is called. We don't need to use it for our purposes.
+ * @file:	The file to be closed.
+ */
+static int mausb_release(struct inode *inode, struct file *file)
+{
+	ma_open--;
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+/**
+ * This function is used to read from the device file. From the perspective of
+ * the device, the user is reading information from us. This is one of the
+ * entry points to this module.
+ *
+ * @file:	The device file. We don't use it directly, but it's passed in.
+ * @buffer:	The buffer to put the message into.
+ * @length:	The max length to be read.
+ * @offset:	File offset, which we don't use but it is passed in nontheless.
+ */
+static ssize_t mausb_read(struct file *file, char __user *buffer,
+		size_t length, loff_t *offset)
+{
+	int bytes_read = 0;
+
+	if (*message_point == 0)
+		return 0;
+	while (length && *message_point) {
+		put_user(*(message_point++), buffer++);
+		length--;
+		bytes_read++;
+	}
+
+	return bytes_read;
+}
+
+/**
+ * This function is used to write to the device file. From the perspective of
+ * the device, the user is writing information to us. This is one of the
+ * entry points to this module.
+ *
+ * @file:	The device file. We don't use it directly, but it's passed in.
+ * @buffer:	The buffer that holds the message.
+ * @length:	The length of the message to be written.
+ * @offset:	File offset, which we don't use but it is passed in nontheless.
+ */
+static ssize_t mausb_write(struct file *file, const char __user *buffer,
+		size_t length, loff_t *offset)
+{
+	int i;
+
+	for (i = 0; i < length && i < BUFFER; i++)
+		get_user(message[i], buffer + i);
+	message_point = message;
+
+	return i;
+}
+
+/**
+ * This function is used to execute ioctl commands, determined by ioctl_func.
+ *
+ * @file:	  The device file. We don't use it directly, but it's passed in.
+ * @ioctl_func:	  This value determines which ioctl function will be used.
+ * @ioctl_buffer: This buffer is used to transfer data to/from the device.
+ */
+long mausb_ioctl(struct file *file, unsigned int ioctl_func,
+		unsigned long ioctl_buffer)
+{
+	int bytes = 0;
+	char *msg, *ip_addr;
+	char chr;
+	int ret, value;
+	unsigned long int  long_ret;
+
+	switch (ioctl_func) {
+	case IOCTL_SET_MSG:
+		msg = (char *)ioctl_buffer;
+		get_user(chr, msg);
+		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
+			get_user(chr, msg);
+		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
+		break;
+	case IOCTL_GET_MSG:
+		bytes = mausb_read(file, (char *)ioctl_buffer, 99, 0);
+		put_user('\0', (char *)ioctl_buffer + bytes);
+		break;
+	case IOCTL_GET_VRSN:
+		to_user(DRIVER_VERSION, ioctl_buffer);
+		break;
+	case IOCTL_GET_NAME:
+		to_user(MAUSB_NAME, ioctl_buffer);
+		break;
+	case IOCTL_GADGET_C:
+		ret = gadget_connection(1);
+		if (ret >= 0)
+			to_user("g_zero connect process complete", ioctl_buffer);
+		else
+			to_user("g_zero connect process failed", ioctl_buffer);
+		break;
+	case IOCTL_GADGET_D:
+		ret = gadget_connection(0);
+		if (ret >= 0)
+			to_user("g_zero disconnect process complete",
+				ioctl_buffer);
+		else
+			to_user("g_zero disconnect process failed",
+				ioctl_buffer);
+		break;
+	case IOCTL_MED_DELAY:
+		msg = (char *)ioctl_buffer;
+		get_user(chr, msg);
+		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
+			get_user(chr, msg);
+		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
+		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
+			/* TODO: handle error */
+		}
+		ret = set_medium_delay(value);
+		sprintf(message_point, "DELAY VALUE: ms: %d, jiffies: %d\n",
+			value, ret);
+		to_user(message_point, ioctl_buffer);
+		break;
+	case IOCTL_SET_IP:
+		msg = (char *)ioctl_buffer;
+		get_user(chr, msg);
+		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
+			get_user(chr, msg);
+		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
+		ip_addr = kmalloc(strlen(message_point)+1, GFP_KERNEL);
+		if (!ip_addr) {
+			printk(KERN_ALERT "Memory allocation failed!\n");
+			break;
+		}
+		strcpy(ip_addr, message_point);
+		sprintf(message_point, "Connecting to ...\nIP Address: %s\n",
+			ip_addr);
+		to_user(message_point, ioctl_buffer);
+		kfree(ip_addr);
+		break;
+	case IOCTL_SET_PORT:
+		msg = (char *)ioctl_buffer;
+		get_user(chr, msg);
+		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
+			get_user(chr, msg);
+		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
+		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
+			/* TODO: handle error */
+		}
+		ret = set_port_no(value);
+		sprintf(message_point, "PORT NUMBER:%d, Returned %i\n", value,
+			ret);
+		to_user(message_point, ioctl_buffer);
+		break;
+	case IOCTL_SET_IP_DECIMAL:
+		msg = (char *)ioctl_buffer;
+		get_user(chr, msg);
+		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
+			get_user(chr, msg);
+		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
+		if (kstrtoul((const char *)message_point, 0, &long_ret) != 0) {
+			/* TODO: handle error */
+		}
+
+		ret = set_ip_addr(long_ret);
+		sprintf(message_point, "\nDecimal Value:%lx returned %i\n",
+			long_ret, ret);
+		to_user(message_point, ioctl_buffer);
+		break;
+	case IOCTL_SET_MAC:
+		{
+			u8 *mac = kmalloc(6, GFP_KERNEL);
+			u8 *buf = (u8 __user *)ioctl_buffer;
+			int i, ret;
+			if (!mac) {
+				pr_err("Memory allocation failed!\n");
+				break;
+			}
+			ret = copy_from_user(mac, buf, 6);
+			if (ret) {
+				pr_err("copy_from_user failed\n");
+				kfree(mac);
+				break;
+			}
+			for (i = 0; i < ETH_ALEN; i++)
+				pr_info("mac[%d]=0x%x\n", i, mac[i]);
+			ret = set_mac_addr(mac);
+			if (ret)
+				pr_err("unable to set MAC addr\n");
+			kfree(mac);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * This struct creates links with our implementations of various entry point
+ * functions.
+ */
+const struct file_operations fops = {
+	.open = mausb_open,
+	.release = mausb_release,
+	.read = mausb_read,
+	.write = mausb_write,
+	.unlocked_ioctl = mausb_ioctl
+};
+
+/**
+ * Registers a character device using our device file. This function is called
+ * in the mausb_hcd_init function.
+ */
+int reg_chrdev()
+{
+	int ret;
+
+#ifdef MAUSB_PRINT_IOCTL_MAGIC
+
+	printk(KERN_DEBUG "Printing IOCTL magic numbers:\n");
+	printk(KERN_DEBUG "IOCTL_SET_MSG        = %u\n", IOCTL_SET_MSG);
+	printk(KERN_DEBUG "IOCTL_GET_MSG        = %u\n", IOCTL_GET_MSG);
+	printk(KERN_DEBUG "IOCTL_GET_VRSN       = %u\n", IOCTL_GET_VRSN);
+	printk(KERN_DEBUG "IOCTL_GET_NAME       = %u\n", IOCTL_GET_NAME);
+	printk(KERN_DEBUG "IOCTL_GADGET_C       = %u\n", IOCTL_GADGET_C);
+	printk(KERN_DEBUG "IOCTL_GADGET_D       = %u\n", IOCTL_GADGET_D);
+	printk(KERN_DEBUG "IOCTL_MED_DELAY      = %u\n", IOCTL_MED_DELAY);
+	printk(KERN_DEBUG "IOCTL_SET_IP         = %u\n", IOCTL_SET_IP);
+	printk(KERN_DEBUG "IOCTL_SET_PORT       = %u\n", IOCTL_SET_PORT);
+	printk(KERN_DEBUG "IOCTL_SET_IP_DECIMAL = %u\n", IOCTL_SET_IP_DECIMAL);
+	printk(KERN_DEBUG "IOCTL_SET_MAC        = %u\n", IOCTL_SET_MAC);
+
+#endif
+
+	ret = register_chrdev(MAJOR_NUM, MAUSB_NAME, &fops);
+
+	if (ret < 0)
+		printk(KERN_ALERT "Registering mausb failed with %d\n", ret);
+	else
+		printk(KERN_INFO "%s registeration complete. Major device"
+			" number %d.\n", MAUSB_NAME, MAJOR_NUM);
+
+	return ret;
+}
+
+/**
+ * Unregisters the character device when the hcd is unregistered. As hinted,
+ * this function is called in the mausb_hcd_exit function.
+ */
+void unreg_chrdev()
+{
+	unregister_chrdev(MAJOR_NUM, MAUSB_NAME);
+}
diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.h b/drivers/staging/mausb/drivers/mausb_ioctl.h
new file mode 100644
index 0000000..0f26988
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_ioctl.h
@@ -0,0 +1,99 @@
+/* Name:         mausb_ioctl.h
+ * Description:  header file for MA USB ioctl functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MAUSB_IOCTL_H
+#define MAUSB_IOCTL_H
+
+#define BUFFER 80
+#define DRIVER_VERSION "Alpha 0.0.25"
+#define MAJOR_NUM 100
+
+/* These define the ioctl functions that can be used. */
+#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
+#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
+#define IOCTL_GET_VRSN _IOR(MAJOR_NUM, 2, char *)
+#define IOCTL_GET_NAME _IOR(MAJOR_NUM, 3, char *)
+#define IOCTL_GADGET_C _IOR(MAJOR_NUM, 4, char *)
+#define IOCTL_GADGET_D _IOR(MAJOR_NUM, 5, char *)
+#define IOCTL_MED_DELAY _IOR(MAJOR_NUM, 6, char *)
+#define IOCTL_SET_IP _IOR(MAJOR_NUM, 7, char *)
+#define IOCTL_SET_PORT _IOR(MAJOR_NUM, 8, char *)
+#define IOCTL_SET_IP_DECIMAL _IOR(MAJOR_NUM, 9, char *)
+#define IOCTL_SET_MAC _IOR(MAJOR_NUM, 10, char *)
+
+/* This is the location where the device file will be created. It is used to
+ * read/write to in order to communicate to and from the device. */
+#define DEVICE_FILE_NAME "/dev/mausb"
+
+/* MAC address length */
+#define ETH_ALEN 6
+
+/* forward declarations */
+struct mausb_udc;
+struct mausb_hcd;
+
+/* Functions for register/unregistering the character device */
+int reg_chrdev(void);
+void unreg_chrdev(void);
+
+/* Medium-defined functions */
+int set_medium_delay(int delay);
+int set_ip_addr(unsigned long in_addr);
+int set_port_no(int port_no);
+int set_mac_addr(unsigned char mac_addr[ETH_ALEN]);
+int gadget_connection(int on);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_msapi.c b/drivers/staging/mausb/drivers/mausb_msapi.c
new file mode 100644
index 0000000..9dd8fa5
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_msapi.c
@@ -0,0 +1,110 @@
+/* Name:	mausb_msapi.c
+ * Description: This file contains helper functions for using the msapi.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include "mausb_msapi.h"
+
+int mausb_transfer_packet(struct ms_pkt *pkt,
+	struct mausb_pkt_transfer *transfer)
+{
+	return transfer->transfer_packet(pkt, transfer->context);
+}
+EXPORT_SYMBOL(mausb_transfer_packet);
+
+/**
+ * Frees the given ms_pkt and associated buffers. This function is not
+ * necessary to use the API, but could be useful on both sides of the interface.
+ */
+void mausb_free_ms_pkt(struct ms_pkt *pkt)
+{
+	int i;
+	void *current_buf;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_buf = pkt[i].kvec->iov_base;
+		if (NULL != current_buf) {
+			kfree(current_buf);
+		} else {
+			printk(KERN_DEBUG "%s: cannot find buffer for "
+				"kvec #%i in ms_pkt at %p\n",
+				__func__, i, pkt->kvec);
+		}
+	}
+
+	kfree(pkt);
+
+	return;
+}
+EXPORT_SYMBOL(mausb_free_ms_pkt);
+
+/**
+ * Calculates the total length of the data in a ms_pkt. Returns the total
+ * length of the data in the ms_pkt, or a negative errno.
+ */
+int mausb_ms_pkt_length(struct ms_pkt *pkt)
+{
+	int i;
+	int total_length = 0;
+
+	for (i = 0; i < pkt->nents; ++i)
+		total_length += pkt[i].kvec->iov_len;
+
+	printk(KERN_DEBUG "%s: total *kvec length: %i\n", __func__,
+		total_length);
+
+	return total_length;
+}
diff --git a/drivers/staging/mausb/drivers/mausb_msapi.h b/drivers/staging/mausb/drivers/mausb_msapi.h
new file mode 100644
index 0000000..7a9c30c
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_msapi.h
@@ -0,0 +1,232 @@
+/* Name:	mausb_msapi.h
+ * Description: This header describes how the media agnostic driver
+ *              interfaces with a media specific driver.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/********************** Initial MS Registration **********************/
+
+/* The MS driver must initially register with the MA driver to make the
+ * inital connection. this is done via a call to mausb_register_ms_driver
+ * (see mausb_hcd.c for details)
+ */
+
+/************************ Packet Send/Recieve ************************/
+
+/* Packets are transferred between the MS and the MA driver via function
+ * calls into each other. When the MA driver has a packet to send out, it
+ * makes a function call into the MS driver with the packet it wishes to
+ * send. Likewise, the MS driver calls into the MA driver if it needs to
+ * pass it a packet.
+ */
+
+/********************** Transfer Pair Add/Remove *********************/
+
+/*
+ * The MA driver establishes a new transfer pair for every independant
+ * connection (ie: one for every independant endpoint, as well as one
+ * for every device). To establish a new connection, the MA driver
+ * calls into the MS driver with an incomplete mausb_transfer_pair.
+ * this incomplete pair includes only the data needed to call into
+ * the MA driver.
+ */
+
+#ifndef __MAUSB_MSAPI_H
+#define __MAUSB_MSAPI_H
+
+#include <linux/uio.h>
+
+/**
+ * Offset in Bytes of location of length field - streaming mediums need to
+ * know where the length field is in a packet so they can determine where
+ * packets begin and end in the stream.
+ */
+#define MAUSB_PKT_LENGTH_OFFSET 2
+ 
+/* the largest number of segments that will ever be in a mausb packet */
+#define MAUSB_PKT_MAX_NR_SEGS 3
+
+/* This is a convenience structure for keeping the number of entries in
+ * the kvec with its pointer.
+ *
+ * @kvec:	The pointer to the ma_pkt kvec or iovec.
+ * @nents:	The number of entires in the ma_pkt kvec or iovec.
+ */
+struct ms_pkt {
+	union {
+		struct kvec kvec[MAUSB_PKT_MAX_NR_SEGS];
+		struct iovec iovec[MAUSB_PKT_MAX_NR_SEGS];
+	};
+	int nents;
+};
+
+
+/**
+ * This struct defines a one way connection for passing packets from one
+ * driver to the other.
+ *
+ * @transfer_packet:	The function call to use when you want to transmit
+ *                   	a packet.
+ * @context:		The context to use in the function when calling the
+ *           		transfer packet.
+ */
+struct mausb_pkt_transfer {
+	int (*transfer_packet)(struct ms_pkt *pkt, void *context);
+	void *context;
+};
+
+int mausb_transfer_packet(struct ms_pkt *pkt,
+	struct mausb_pkt_transfer *transfer);
+
+/**
+ * This struct defines a pair of connections to and from an independant
+ * endpoint or device.
+ *
+ * @to_ma:	The transfer to use when passing a packet to the MA driver
+ *         	from the MS driver.
+ * @to_ms:	The transfer to use when passing a packet to the MS driver
+ *         	from the MA driver.
+ * @pkt_sent: 	Packet completion routine. Called by the MS driver into
+ *            	the MA driver after the packet has been put onto the medium.
+ * @handle: 	A unique identifier for this particualar transfer pair.
+ *          	In our implementation, we use the EP/Device Handle.
+ *		For the management channel, set handle to MAUSB_MGMT_HANDLE.
+ */
+
+#define MAUSB_MGMT_HANDLE 0
+
+struct mausb_transfer_pair {
+	struct mausb_pkt_transfer to_ma;
+	struct mausb_pkt_transfer to_ms;
+	void                    (*pkt_sent)(struct ms_pkt *pkt);
+	unsigned int              handle;
+};
+
+struct urb;
+
+/**
+ * This struct defines all the calls the MA USB-HCD Driver can make
+ * to a media specific driver.
+ *
+ * @add_transfer_pair:	Used to establish a new transfer pair.
+ *       @tx_pair [IN/OUT]:	An incomplete transfer pair. The MA driver
+ *                          	completes the to_ma field and passes it to
+ *				the MA driver. The MS driver fills the
+ *				to_ma field and returns the pointer.
+ * @drop_transfer_pair: Used to remove an existing transfer pair.
+ *       @handle  [IN]:		The unique identifier of the transfer pair
+ *				to remove.
+ * @pkt_destructor: 	Used to destroy a packet that was received from
+ *			the medium. Acts as a hook to allow the medium to
+ *			free any media specific data for a packet.
+ *       @pkt [IN]		The packet the MA driver wishes to free.
+ */
+struct mausb_ms_ops {
+	int  (*add_transfer_pair)(struct mausb_transfer_pair *tx_pair);
+	int  (*drop_transfer_pair)(unsigned long handle, void *context);
+	void (*pkt_destructor)(struct ms_pkt *pkt);
+};
+
+/**
+ * This struct defines all of the media-specific parameters needed by
+ * the MA driver.
+ *
+ * TODO: add spec-defined and implementation-specific variables
+ */
+struct mausb_ms_params {
+
+
+};
+
+/**
+ * This structure includes all of the data needed by the MA driver to
+ * communicate with the Media Specific Driver.
+ *
+ * @ops:	Contains function pointers to all of the functions the
+ *		MA driver will ever need to call.
+ * @params:	Contains all of the media-specific paramaters that the
+ *		MA driver needs.
+ */
+struct mausb_ms_drv {
+	struct mausb_ms_ops *ops;
+	struct mausb_ms_params *params;
+};
+
+/**
+ * This structure includes all of the ways the Media Specific Driver
+ * is capable of calling to the Media Agnostic Driver.
+ *
+ * @device_connect:	Called to indicate that a device has been connected
+ *			and is ready to receive MA packets.
+ * @pkt_dmux:		Used for passing packets into the driver. It will
+ *			parse the packet to determine what endpoint/device
+ *			it belongs to. Used when the medium cannot keep
+ *			data channels seperate.
+ * @pkt_sent:		Used as a notification that a packet has been sent
+ *			out.
+ */
+struct mausb_ma_drv {
+	int (*device_connect)(int);
+	struct mausb_pkt_transfer pkt_dmux;
+	/* TODO: implement pkt_sent indicator */
+	/* void (*pkt_sent)(struct ms_pkt *pkt); */
+};
+
+/* function declarations */
+struct mausb_ma_drv *mausb_register_ms_driver(struct mausb_ms_drv *drv);
+struct mausb_ma_drv *maudc_register_ms_driver(struct mausb_ms_drv *drv);
+void mausb_free_ms_pkt(struct ms_pkt *pkt);
+int mausb_ms_pkt_length(struct ms_pkt *pkt);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_tcp-device.c b/drivers/staging/mausb/drivers/mausb_tcp-device.c
new file mode 100644
index 0000000..28978a0
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp-device.c
@@ -0,0 +1,147 @@
+/* Name:	mausb_tcp-device.c
+ * Description: The device side media specific driver to allow media agnostic
+ *               packets over tcp/ip.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "mausb_tcp.h"
+#include "mausb_ioctl.h"
+
+struct mausb_tcp_medium *dev_tcp_medium;
+
+int mausb_tcp_device_thread(void *data)
+{
+	return mausb_tcp_receive_loop(dev_tcp_medium);
+}
+
+int mausb_tcp_device_add_tx_pair(struct mausb_transfer_pair *ma_pair)
+{
+	return mausb_tcp_add_tx_pair(ma_pair, dev_tcp_medium);
+}
+
+static struct mausb_ms_ops ms_ops = {
+	.add_transfer_pair = &mausb_tcp_device_add_tx_pair,
+	.drop_transfer_pair = &mausb_tcp_drop_tx_pair,
+	.pkt_destructor = &mausb_free_ms_pkt
+};
+
+static struct mausb_ms_drv ms_driver = {
+	.ops =  &ms_ops
+};
+
+static int mausb_tcp_device_connect(int on)
+{
+	int ret;
+
+	if (on && dev_tcp_medium->socket == NULL) {
+		ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
+			&dev_tcp_medium->socket);
+
+		if (0 > ret) /* TODO: real errorchecking */
+			return ret;
+
+		do {
+			ret = kernel_connect(dev_tcp_medium->socket,
+				&dev_tcp_medium->addr,
+				sizeof(dev_tcp_medium->addr_in), O_RDWR);
+			printk(KERN_DEBUG "%s:kernel_connect returned %i\n",
+				__func__, ret);
+
+			if (0 > ret) {
+				/* poll until we can connect sucessfully */
+				msleep(MAUSB_TCP_DEV_CONNECT_POLL_MS);
+			}
+
+
+		} while (0 > ret);
+
+		/*spawn off a listening thread */
+		dev_tcp_medium->recv_task = kthread_run(mausb_tcp_device_thread,
+			NULL, "mausb_tcp_device_thread");
+	}
+
+	ret = dev_tcp_medium->ma_driver->device_connect(on);
+
+	return ret;
+}
+
+int mausb_tcp_device_init(void)
+{
+	dev_tcp_medium = alloc_init_mausb_tcp_medium(MAUSB_TCP_DEV);
+	if (NULL == dev_tcp_medium)
+		return -ENOMEM;
+
+	dev_tcp_medium->addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	dev_tcp_medium->connect = &mausb_tcp_device_connect;
+
+	dev_tcp_medium->ma_driver = maudc_register_ms_driver(&ms_driver);
+
+
+	return 0;
+}
+module_init(mausb_tcp_device_init);
+
+void mausb_tcp_device_exit(void)
+{
+	free_mausb_tcp_medium(dev_tcp_medium, MAUSB_TCP_DEV);
+}
+module_exit(mausb_tcp_device_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_device");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp-host.c b/drivers/staging/mausb/drivers/mausb_tcp-host.c
new file mode 100644
index 0000000..0302031
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp-host.c
@@ -0,0 +1,144 @@
+/* Name:	mausb_tcp-host.c
+ * Description: The host side media specific driver to allow media agnostic
+ *              packets over tcp/ip.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "mausb_tcp.h"
+
+struct mausb_tcp_medium *host_tcp_medium;
+
+int mausb_tcp_host_thread(void *data)
+{
+	return mausb_tcp_receive_loop(host_tcp_medium);
+}
+
+int mausb_tcp_host_add_tx_pair(struct mausb_transfer_pair *ma_pair)
+{
+	return mausb_tcp_add_tx_pair(ma_pair, host_tcp_medium);
+}
+
+static struct mausb_ms_ops ms_ops = {
+	.add_transfer_pair = &mausb_tcp_host_add_tx_pair,
+	.drop_transfer_pair = &mausb_tcp_drop_tx_pair,
+	.pkt_destructor = &mausb_free_ms_pkt
+};
+
+static struct mausb_ms_drv ms_driver = {
+	.ops =  &ms_ops
+};
+
+static int mausb_tcp_host_connect(int on)
+{
+	int ret;
+
+	if (on) {
+		ret = kernel_bind(host_tcp_medium->setup_socket,
+			&host_tcp_medium->addr,
+			sizeof(host_tcp_medium->addr_in));
+
+		ret = kernel_listen(host_tcp_medium->setup_socket,
+			MAUSB_TCP_MAX_NUM_CHANNELS);
+		printk(KERN_DEBUG "%s: kernel_listen returned %i\n",
+			__func__, ret);
+
+		ret = kernel_accept(host_tcp_medium->setup_socket,
+				    &host_tcp_medium->socket, 0);
+		printk(KERN_DEBUG "%s:kernel_accept returned %i\n",
+			__func__, ret);
+
+		if (0 > ret)
+			return ret;
+
+		if (NULL == host_tcp_medium->recv_task) {
+			host_tcp_medium->recv_task = kthread_run(
+				mausb_tcp_host_thread, NULL,
+				"mausb_tcp_host_thread");
+		}
+	}
+
+	ret = host_tcp_medium->ma_driver->device_connect(on);
+
+	return ret;
+}
+
+int mausb_tcp_host_init(void)
+{
+	host_tcp_medium = alloc_init_mausb_tcp_medium(MAUSB_TCP_HOST);
+	if (NULL == host_tcp_medium)
+		return -ENOMEM;
+
+	host_tcp_medium->addr_in.sin_addr.s_addr = htonl(0);
+
+	host_tcp_medium->connect = &mausb_tcp_host_connect;
+
+	host_tcp_medium->ma_driver = mausb_register_ms_driver(&ms_driver);
+
+	return 0;
+
+}
+module_init(mausb_tcp_host_init);
+
+void mausb_tcp_host_exit(void)
+{
+	free_mausb_tcp_medium(host_tcp_medium, MAUSB_TCP_HOST);
+}
+module_exit(mausb_tcp_host_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_host");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp.c b/drivers/staging/mausb/drivers/mausb_tcp.c
new file mode 100644
index 0000000..291139e
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp.c
@@ -0,0 +1,446 @@
+/* Name:	mausb_tcp.c
+ * Description: This is a driver used to connect an MA USB driver to a tcp
+ *              socket.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/uio.h>
+#include <linux/delay.h>
+
+#include "mausb_ioctl.h"
+#include "mausb_tcp.h"
+
+struct mausb_tcp_medium *tcp_medium[MAUSB_TCP_NUM_MODS];
+
+static int gadget_connect_thread(void *data_p)
+{
+	struct mausb_connect_data *data = data_p;
+	int ret;
+
+	printk(KERN_DEBUG "%s: Running thread #%i\n", __func__, data->i);
+
+	ret = tcp_medium[data->i]->connect(data->on);
+
+	printk(KERN_DEBUG "%s: Thread #%i complete, returing with value %i\n",
+		__func__, data->i, ret);
+
+	kfree(data);
+
+	return ret;
+}
+
+/* for IOCTL */
+int gadget_connection(int on)
+{
+	int i;
+
+	struct mausb_connect_data *data;
+
+	/* make all the calls */
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+
+		if (NULL != tcp_medium[i] &&
+			NULL != tcp_medium[i]->ma_driver) {
+
+			data = kzalloc(sizeof(*data), GFP_KERNEL);
+			if (NULL == data)
+				return -ENOMEM;
+
+			data->task = NULL;
+			data->on = on;
+			data->i = i;
+
+			printk(KERN_DEBUG "%s: spawning thread #%i\n",
+				__func__, i);
+
+			data->task = kthread_run(gadget_connect_thread,
+				data, "mausb_connect_thread_%i", i);
+		}
+	}
+
+	return 0;
+}
+
+/* for IOCTL */
+int set_medium_delay(int delay)
+{
+	printk(KERN_DEBUG "%s: ERROR: cannot set latency of real medium\n",
+		__func__);
+	return -EINVAL;
+}
+
+int set_port_no(int port)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+		if (NULL != tcp_medium[i]) {
+			tcp_medium[i]->addr_in.sin_port = htons(port);
+			ret = port;
+		}
+	}
+
+	return ret;
+}
+
+int set_ip_addr(unsigned long in_addr)
+{
+	int ret = -EINVAL;
+	int i;
+	struct in_addr addr;
+
+	addr.s_addr = htonl(in_addr);
+
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+		if (NULL != tcp_medium[i]) {
+			tcp_medium[i]->addr_in.sin_addr = addr;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+int set_mac_addr(unsigned char mac_addr[ETH_ALEN])
+{
+	printk(KERN_DEBUG "%s: ERROR: cannot set mac address for TCP\n",
+		__func__);
+	return -EINVAL;
+}
+
+inline void *mausb_tcp_to_context(struct mausb_tcp_medium *medium)
+{
+	return (void *) medium;
+}
+EXPORT_SYMBOL(mausb_tcp_to_context);
+
+inline struct mausb_tcp_medium *mausb_context_to_tcp(void *context)
+{
+	return (struct mausb_tcp_medium *) context;
+}
+EXPORT_SYMBOL(mausb_context_to_tcp);
+
+static void mausb_tcp_init_msg(struct msghdr *msg)
+{
+	msg->msg_name = NULL;
+	msg->msg_namelen = 0;
+	msg->msg_control = NULL;
+	msg->msg_controllen = 0;
+	msg->msg_flags = 0;
+}
+
+static int mausb_tcp_enqueue(struct ms_pkt *pkt, void *context)
+{
+	struct msghdr msg;
+	struct mausb_tcp_medium *tcp_medium;
+	int total_length = 0;
+	int ret = 0;
+	int i;
+
+	mausb_tcp_init_msg(&msg);
+
+	if (NULL == context) {
+		printk(KERN_DEBUG "%s: ERROR: null context\n", __func__);
+		return -EINVAL;
+	}
+	tcp_medium = mausb_context_to_tcp(context);
+
+	if (NULL == tcp_medium->socket) {
+		printk(KERN_DEBUG "%s: ERROR: no socket for packet\n",
+			__func__);
+		return -ENOTCONN;
+	}
+
+	for (i = 0; i < pkt->nents; ++i) {
+		total_length += pkt->kvec[i].iov_len;
+	}
+
+	ret = kernel_sendmsg(tcp_medium->socket, &msg, pkt->kvec, pkt->nents,
+		total_length);
+
+	printk(KERN_DEBUG "%s: sent %i bytes\n", __func__, ret);
+
+	/*
+	 * TODO: implement completion (pkt_sent) callback
+	 * if (NULL != tcp_medium->tx_pair.pkt_sent && 0 < ret)
+	 * tcp_pair->tx_pair.pkt_sent(pkt);
+	 */
+
+	return ret;
+}
+
+static int mausb_tcp_receive_packet(struct mausb_tcp_medium *tcp_medium,
+		struct msghdr *msg, struct ms_pkt *pkt)
+{
+	struct kvec kvec;
+	int data_rcvd;
+	int total_rcvd = 0;
+	__u16 length;
+	void *buf;
+
+	buf = kmalloc(MAUSB_TCP_BUF_SIZE, GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+
+	kvec.iov_base = buf;
+	kvec.iov_len = MAUSB_TCP_BUF_SIZE;
+
+	/* receive the first DWORD to determine length */
+	data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec, 1,
+					sizeof(__u32), MSG_DONTWAIT);
+
+	while (data_rcvd == -EAGAIN && !kthread_should_stop()) {
+		/* sleep to prevent excessive polling */
+		msleep(10);
+
+		/* receive the first DWORD to determine length */
+		data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec,
+				1, sizeof(__u32), MSG_DONTWAIT);
+	}
+
+	if (0 > data_rcvd) {
+		printk(KERN_DEBUG "%s: ERROR: Could not read packet length"
+			" (error #%i)\n", __func__, data_rcvd);
+		kfree(buf);
+		return data_rcvd;
+	}
+
+	/* the data is invalid */
+	if (sizeof(__u32) > data_rcvd) {
+		printk(KERN_DEBUG "%s: ERROR: did not read enough data"
+			" to get length (received %i bytes)\n", __func__,
+			data_rcvd);
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	length = le16_to_cpu(*((__le16 *)(buf + MAUSB_PKT_LENGTH_OFFSET)));
+	total_rcvd += data_rcvd;
+
+	/* make sure length is valid */
+	if (length < sizeof(__u32)) {
+		printk(KERN_DEBUG "%s: ERROR: length field too small (%u)\n",
+			 __func__, length);
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	/* receive the remainder of the packet */
+	while (total_rcvd < length && total_rcvd >= 0 &&
+		!kthread_should_stop()) {
+
+		data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec,
+			1, length - total_rcvd, 0);
+
+		if (0 < data_rcvd) {
+			total_rcvd += data_rcvd;
+
+		} else if (0 > data_rcvd) {
+			printk(KERN_DEBUG "%s: ERROR: while receiving packet "
+			"(err #%i)\n", __func__, data_rcvd);
+			kfree(buf);
+			return data_rcvd;
+		}
+	}
+
+	if (total_rcvd != length) {
+		printk(KERN_DEBUG "%s: Warning: did not receive enough data "
+			"(length:%u, received:%i)\n", __func__,
+			length, total_rcvd);
+	}
+
+
+	pkt->nents = 1;
+	pkt->kvec[0].iov_base = buf;
+	pkt->kvec[0].iov_len = total_rcvd;
+
+	return total_rcvd;
+}
+
+int mausb_tcp_receive_loop(struct mausb_tcp_medium *tcp_medium)
+{
+	struct msghdr msg;
+	struct ms_pkt *pkt;
+	int data_rcvd = 0;
+
+	mausb_tcp_init_msg(&msg);
+
+	while (!kthread_should_stop()) {
+
+		pkt = kzalloc(sizeof(struct ms_pkt), GFP_KERNEL);
+
+		printk(KERN_DEBUG "%s: preparing to receive data\n",
+			__func__);
+
+		data_rcvd = mausb_tcp_receive_packet(tcp_medium, &msg, pkt);
+
+		if (0 >= data_rcvd) {
+			printk(KERN_DEBUG "%s: received no data (err %i)\n",
+				__func__, data_rcvd);
+
+			sock_release(tcp_medium->socket);
+			return data_rcvd;
+
+		} else {
+			printk(KERN_DEBUG "%s: received %i bytes\n",
+				__func__, data_rcvd);
+		}
+
+		if (data_rcvd > 0) {
+			mausb_transfer_packet(pkt,
+				&tcp_medium->ma_driver->pkt_dmux);
+		}
+
+		data_rcvd = 0;
+	}
+
+	sock_release(tcp_medium->socket);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_receive_loop);
+
+int mausb_tcp_add_tx_pair(struct mausb_transfer_pair *ma_pair,
+	struct mausb_tcp_medium *medium)
+{
+	ma_pair->to_ms.transfer_packet = &mausb_tcp_enqueue;
+	ma_pair->to_ms.context = mausb_tcp_to_context(medium);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_add_tx_pair);
+
+int mausb_tcp_drop_tx_pair(unsigned long handle, void *context)
+{
+	/* TODO: something here */
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_drop_tx_pair);
+
+/**
+ * initialization function
+ */
+struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
+	enum mausb_tcp_module_type type)
+{
+	struct mausb_tcp_medium *medium;
+	int ret;
+
+	printk(KERN_DEBUG "%s\n", __func__);
+
+	medium = kzalloc(sizeof(struct mausb_tcp_medium), GFP_KERNEL);
+	if (NULL == medium) {
+		printk(KERN_DEBUG "%s: memory allocation failed\n", __func__);
+		return NULL;
+	}
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
+		&medium->setup_socket);
+
+	medium->addr_in.sin_family = AF_INET;
+	medium->addr_in.sin_port = htons(MAUSB_TCP_PORT_HOST);
+
+	spin_lock_init(&medium->lock);
+
+	tcp_medium[type] = medium;
+
+	return medium;
+}
+EXPORT_SYMBOL(alloc_init_mausb_tcp_medium);
+
+/**
+ * exit function
+ */
+void free_mausb_tcp_medium(struct mausb_tcp_medium *medium,
+	enum mausb_tcp_module_type type)
+{
+	if (medium->recv_task)
+		kthread_stop(medium->recv_task);
+
+	if (medium->setup_socket)
+		sock_release(medium->setup_socket);
+
+	tcp_medium[type] = NULL;
+
+	kfree(medium);
+}
+EXPORT_SYMBOL(free_mausb_tcp_medium);
+
+int mausb_tcp_core_init(void)
+{
+	int ret;
+
+	ret = reg_chrdev();
+	if (0 > ret) {
+		printk(KERN_DEBUG "%s: reg_chrdev() failed\n",
+			__func__);
+	}
+
+	return ret;
+
+}
+module_init(mausb_tcp_core_init);
+
+void mausb_tcp_core_exit(void)
+{
+	unreg_chrdev();
+}
+module_exit(mausb_tcp_core_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_core");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp.h b/drivers/staging/mausb/drivers/mausb_tcp.h
new file mode 100644
index 0000000..879a7fa
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp.h
@@ -0,0 +1,129 @@
+/* Name: mausb_tcp.h
+ * Description: header file for mausb_tcp.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_TCP_H
+#define __MAUSB_TCP_H
+
+#include <linux/net.h>
+#include <linux/kthread.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+
+#include "mausb_msapi.h"
+
+#define MAUSB_TCP_PORT_HOST 9001
+
+/* used to determine how many times we have to listen */
+#define MAUSB_TCP_MAX_NUM_CHANNELS 1
+
+/* how often the device should poll while connecting */
+#define MAUSB_TCP_DEV_CONNECT_POLL_MS 100
+
+/* how often to poll the port to check for a new message */
+#define MAUSB_TCP_POLL_PORT_MS 5
+
+#define MAUSB_TCP_BUF_SIZE PAGE_SIZE
+
+#define MAUSB_MAX_NAME_LEN 50
+
+#define MAUSB_TCP_RECV_POLL 1 /* in ms */
+
+#define MAUSB_DWORD_LENGTH 4 /* DWORD = 4 bytes */
+
+enum mausb_tcp_module_type {
+	MAUSB_TCP_DEV = 0,
+	MAUSB_TCP_HOST,
+	MAUSB_TCP_NUM_MODS
+};
+
+struct mausb_tcp_medium {
+	struct socket *setup_socket;
+	union {
+		struct sockaddr_in addr_in;
+		struct sockaddr addr;
+	};
+	spinlock_t lock;
+	struct mausb_ma_drv *ma_driver;
+
+	struct socket *socket;
+	struct task_struct *recv_task;
+
+	/* function call for when a device connect/disconnect is made */
+	int (*connect)(int on);
+};
+
+/* Used so that host and device side connect functions can run simultaniously.
+ * See gadget_connection() & gadget_connect_thread() for details. */
+struct mausb_connect_data {
+	struct task_struct *task;
+	int i;
+	int on;
+};
+
+/* function declarations */
+struct mausb_tcp_medium *mausb_tcp_get_medium(void);
+void *mausb_tcp_to_context(struct mausb_tcp_medium *medium);
+struct mausb_tcp_medium *mausb_context_to_tcp(void *context);
+int mausb_tcp_receive_loop(struct mausb_tcp_medium *medium);
+int mausb_tcp_add_tx_pair(struct mausb_transfer_pair *ma_pair,
+		struct mausb_tcp_medium *medium);
+int mausb_tcp_drop_tx_pair(unsigned long handle, void *context);
+struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
+		enum mausb_tcp_module_type type);
+void free_mausb_tcp_medium(struct mausb_tcp_medium *medium,
+		enum mausb_tcp_module_type type);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 06/10] added media agnostic (MA) UDC
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (4 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

This is where we implement the behavior of a USB device controller for
the MA USB device-side driver. The MA UDC interfaces with a gadget driver
and appears to the driver as a regular UDC. However, instead of sending
USB packets over a wired USB bus, the MA UDC hands MA USB packets off to
a media specific layer for transport.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_udc.c | 1488 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_udc.h |  147 +++
 2 files changed, 1635 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.h

diff --git a/drivers/staging/mausb/drivers/mausb_udc.c b/drivers/staging/mausb/drivers/mausb_udc.c
new file mode 100644
index 0000000..dd8bd02
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_udc.c
@@ -0,0 +1,1488 @@
+/* name:	mausb_udc.c
+ * description: Implements a USB device controller(UDC) for interfacing with
+ *		gadget drivers. The gadget driver uses this interface to return
+ *		descriptors and to implement configuration and data transfer
+ *		protocols with the pHCD. The UDC also allocates and initializes
+ *		endpoints to support gadget/pHCD interfacing.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.o.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/gadget.h>
+#include <linux/device.h>
+#include <linux/usb/composite.h>
+#include <linux/spinlock.h>
+
+#include "mausb_udc.h"
+#include "mausb_mgmt.h"
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+#include "mausb_tx.h"
+
+static const char	 ep0[] = "ep0";
+static const char *const ep_name[] = {ep0, "ep1", "ep2"};
+
+static struct platform_device udc_pdev;
+
+void udc_dev_release(struct device *dev)
+{
+	/* free any dynamically allocated structures here */
+}
+
+static inline struct mausb_udc *gadget_to_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct mausb_udc, gadget);
+}
+
+static inline struct mausb_udc *gadget_dev_to_mausb_udc(struct device *dev)
+{
+	return container_of(dev, struct mausb_udc, gadget.dev);
+}
+
+static inline struct mausb_request *usb_req_to_mausb_req(
+		struct usb_request *req)
+{
+	return container_of(req, struct mausb_request, req);
+}
+
+static inline struct mausb_udc *mausb_ma_dev_to_udc(struct ma_dev *ma_dev)
+{
+	return container_of(ma_dev, struct mausb_udc, ma_dev);
+}
+
+/*
+ * forward declarations
+ */
+static int set_or_clear_gadget_feature(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc, int set);
+static int get_gadget_status(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc);
+
+/**
+ * Finds a matching endpoint for a given address.
+ */
+static struct usb_ep *get_ep(struct mausb_udc *udc, u8 address)
+{
+	int			i;
+	struct usb_ep		*ep;
+
+	/* address is 0 (ignore direction bit flag) */
+	if ((address & ~USB_DIR_IN) == 0)
+		return &udc->usb_ep[0].dev_ep;
+
+	/* otherwise look for match */
+	for (i = 1; i < MAUDC_MAX_NUM_EP; i++) {
+
+		ep = &udc->usb_ep[i].dev_ep;
+
+		if (ep->address == address)
+			return ep;
+	}
+
+	maudc_dbg(udc, "%s: no endpoint found for address 0x%x\n",
+		__func__, address);
+
+	return NULL;
+}
+
+/**
+ * Called by gadget driver to enable endpoint.
+ */
+static int mausb_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep		*ma_ep = mausb_find_ep_by_desc(desc,
+						udc->mausb_dev);
+
+	maudc_dbg(udc, "%s: enabling gadget endpoint %s\n",
+		__func__, ep->name);
+
+	/* ep0 is control endpoint, don't try and configure it */
+	if (ep->name == ep0) {
+		maudc_err(udc, "%s: cannot configure ep0\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Get maximum packet size from descriptor and set for ep.
+	 * Bits 0->10 of wMaxPacketSize = maximum packet size for HS and
+	 * FS devices maximum packet size for SS devices = 1024.
+	 */
+	ep->maxpacket = EP_MAX_PACKET;
+
+	if (NULL != ma_ep)
+		mausb_link_ma_ep_to_usb_ep(ma_ep, ep);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to disable endpoint.
+ */
+static int mausb_ep_disable(struct usb_ep *ep)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (!ep) {
+		maudc_dbg(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	maudc_dbg(udc, "%s: disabling gadget endpoint %s\n",
+		__func__, ep->name);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to allocate a request packet.
+ */
+static struct usb_request *mausb_ep_alloc_request(struct usb_ep *ep,
+		gfp_t mem_flags)
+{
+	struct mausb_request *req;
+
+	if (!ep)
+		return NULL;
+
+	req = kzalloc(sizeof(*req), mem_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->usb_req_list);
+
+	return &req->req;
+}
+
+/**
+ * Called by gadget driver to free a request packet.
+ */
+static void mausb_ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mausb_request *mreq;
+
+	if (!ep || !req)
+		return;
+
+	mreq = usb_req_to_mausb_req(req);
+	kfree(mreq);
+}
+
+/**
+ * Called by gadget driver to queue a request.
+ */
+static int mausb_ep_queue(struct usb_ep *ep, struct usb_request *req,
+		gfp_t mem_flags)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_request		*ma_req;
+	struct mausb_gadget_ep		*gadget_ep;
+
+	if (!ep) {
+		maudc_err(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!req) {
+		maudc_err(udc, "%s: no USB request\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_req = usb_req_to_mausb_req(req);
+	gadget_ep = usb_ep_to_mausb_gadget_ep(ep);
+
+	req->status = -EINPROGRESS;
+	req->actual = 0;
+
+	maudc_dbg(udc, "%s: queueing request to ep %i at 0x%p with data at "
+		"0x%p\n", __func__, usb_endpoint_num(ep->desc), ep, req->buf);
+
+	list_add_tail(&ma_req->usb_req_list, &gadget_ep->usb_req_list);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to dequeue a request.
+ */
+static int mausb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_request		*ma_req;
+
+	if (!ep) {
+		maudc_err(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!req) {
+		maudc_err(udc, "%s: no USB request\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_req = usb_req_to_mausb_req(req);
+
+	list_del(&ma_req->usb_req_list);
+
+	maudc_dbg(udc, "%s: dequeueing request\n", __func__);
+
+	return 0;
+}
+
+/**
+ * Halts or clears a halt of an endpoint.
+ */
+static int mausb_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct mausb_udc 	*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(ep, udc->mausb_dev);
+
+	if (NULL == ma_ep) {
+		maudc_err(udc, "%s: no MA USB endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	/* probably don't want to halt default control ep */
+	if (ma_ep->dev_ep->name == ep0) {
+		maudc_err(udc, "%s: cannot halt ep0!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (value) {
+		maudc_dbg(udc, "%s: halting ep\n", __func__);
+		ma_ep->halted = 1;
+	}
+
+	else {
+		maudc_dbg(udc, "%s: clearing ep halt\n", __func__);
+		ma_ep->halted = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Wedges an endpoint; wedge causes request to clear halt from host to be
+ * ignored.
+ */
+static int mausb_ep_set_wedge(struct usb_ep *ep)
+{
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(ep, udc->mausb_dev);
+
+	if (NULL == ma_ep) {
+		maudc_err(udc, "%s: no MA USB endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	/* wedging default control ep is probably bad */
+	if (ma_ep->dev_ep->name == ep0) {
+		maudc_dbg(udc, "%s: cannot wedge ep0\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_ep->halted = 1;
+	ma_ep->wedged = 1;
+
+	return 0;
+}
+
+static struct usb_ep_ops mausb_ep_ops = {
+	.enable = mausb_ep_enable,
+	.disable = mausb_ep_disable,
+	.alloc_request = mausb_ep_alloc_request,
+	.free_request = mausb_ep_free_request,
+	.queue = mausb_ep_queue,
+	.dequeue = mausb_ep_dequeue,
+	.set_halt = mausb_ep_set_halt,
+	.set_wedge = mausb_ep_set_wedge
+};
+
+/*---------------------- transfer operations ------------------------------*/
+
+/**
+ * Handles control requests from usb core. Returns 0 if request is fully
+ * handled, otherwise returns the length of the transfer
+ */
+static int handle_ma_control_request(struct mausb_host_ep *ep,
+		struct usb_ctrlrequest *ctrlreq)
+{
+	int			ret = 0;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+
+	if (!ctrlreq) {
+		maudc_err(udc, "%s: no control request\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * UDC handles set/clear feature, get status, and set address
+	 * requests, anything else is passed to gadget driver.
+	 */
+	switch (ctrlreq->bRequest) {
+	case USB_REQ_CLEAR_FEATURE:
+		maudc_dbg(udc, "USB_REQ: clearing feature\n");
+		ret = set_or_clear_gadget_feature(ctrlreq, udc, 0);
+		break;
+
+	case USB_REQ_GET_STATUS:
+		maudc_dbg(udc, "USB_REQ: getting status\n");
+		ret = get_gadget_status(ctrlreq, udc);
+		break;
+
+	case USB_REQ_SET_FEATURE:
+		maudc_dbg(udc, "USB_REQ: setting feature\n");
+		ret = set_or_clear_gadget_feature(ctrlreq, udc, 1);
+		break;
+
+	default: /* pass the request to the gadget driver */
+		maudc_dbg(udc, "USB_REQ: forwarding REQ #%i to gadget driver\n",
+				ctrlreq->bRequest);
+		if (NULL != udc->driver)
+			ret = udc->driver->setup(&udc->gadget, ctrlreq);
+		else
+			maudc_err(udc, "gadget driver not found\n");
+
+		if (ret >= 0)
+			ret = ctrlreq->wLength;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Transfers contents of request and endpoint buffers.
+ */
+int do_ma_transfer(struct mausb_host_ep *ep, struct mausb_pkt *tx_req,
+		bool dir_in)
+{
+	int				i = 0;
+	int				out_copy_length = 0;
+	int				ret, host_len, device_len;
+	int				status = -EINPROGRESS;
+	int				length = 0;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+	struct mausb_request		*req, *next;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	void				*epbuf, *rbuf;
+
+	/* look for setup data */
+	if (tx_req->setup)
+		ret = handle_ma_control_request(ep, tx_req->setup);
+
+	if (NULL == ep->usb_req_list)
+		return -ENOTCONN;
+
+	if (list_empty(ep->usb_req_list) && !in_interrupt()) {
+		maudc_dbg(udc, "wait gadget function driver submit request\n");
+		while (list_empty(ep->usb_req_list) &&
+		       i <= MAUSB_GADGET_TIMEOUT) {
+			msleep(1);
+			i++;
+		}
+	}
+	if (i > MAUSB_GADGET_TIMEOUT) {
+		maudc_dbg(udc, "Wait gadget request time out\n");
+		return -ETIMEDOUT;
+	}
+
+ loop_request_queue:
+	/* take care of each request in request queue */
+	list_for_each_entry_safe(req, next, ep->usb_req_list, usb_req_list) {
+
+		if (dir_in)
+			host_len = tx_state->rem_size - ep->actual_length;
+		else
+			host_len = tx_req->buffer_length - out_copy_length;
+		device_len = req->req.length - req->req.actual;
+		length = min(host_len, device_len);
+
+		/* there is something to transfer so do transfer */
+		if (length > 0) {
+
+			rbuf = req->req.buf + req->req.actual;
+
+			/*
+			 * If IN transfer, copy req buffer contents into
+			 * ep buffer. Vice versa for OUT transfer.
+			 */
+			if (dir_in) {
+				epbuf = ep->buffer + ep->actual_length;
+				if (epbuf)
+					memcpy(epbuf, rbuf, length);
+				else
+					maudc_err(udc, "%s: no ep buffer\n",
+						__func__);
+			} else {
+				/*
+				 * For bulk OUT, we can't use ep->actual_length
+				 * as indicator because ep->buffer for every
+				 * transfer request is only "rx_buf_size" bytes
+				 * length.
+				 */
+				epbuf = ep->buffer + out_copy_length;
+				memcpy(rbuf, epbuf, length);
+				out_copy_length += length;
+			}
+			ep->actual_length += length;
+			req->req.actual += length;
+		}
+		/* zero length packet ends a read */
+		else {
+			req->req.status = 0;
+			status = 0;
+		}
+
+		/*
+		 * A transfer usually ends when buffer contents are completely
+		 * transferred. But, look out for for the zero packet transfer
+		 * flag. If flag is set, bulk OUT transfers need to wait for
+		 * zero length packet (short packet) for completion.
+		 */
+		if ((req->req.length == req->req.actual) ||
+		    /* bulk IN short packet */
+		    (dir_in && (req->req.actual % ep->dev_ep->maxpacket)) ||
+		    /* bulk OUT transfer all data requested by host urb*/
+		    (!dir_in && ep->active_transfer->transfer_size
+		     == ep->actual_length) ||
+		    /* bulk OUT last request */
+		    (!dir_in && req->req.zero)) {
+			req->req.status = 0;
+			/* device completion */
+			list_del_init(&req->usb_req_list);
+			req->req.complete(ep->dev_ep, &req->req);
+		}
+
+		if (tx_state->rem_size == 0)
+			status = 0;
+
+		/*
+		 * Host completion - end when nothing left to read/write,
+		 * otherwise keep going through queue.
+		 */
+		if (status != -EINPROGRESS)
+			break;
+		/* bulk IN/OUT transfers last request serves for one host urb */
+		if (tx_state->rem_size == req->req.actual) {
+			maudc_dbg(udc, "bulk IN/OUT last request return\n");
+			break;
+		}
+		/* bulk IN short packet */
+		if (dir_in && (req->req.actual % ep->dev_ep->maxpacket)) {
+			maudc_dbg(udc, "bulk IN short packet return\n");
+			break;
+		}
+		/*
+		 * Bulk OUT transfer contains multiple bulk OUT MA requests.
+		 * So for bulk out MA request just return to serve subsequent
+		 * bulk out MA request.
+		 */
+		if (!dir_in && host_len == length) {
+			maudc_dbg(udc, "normal bulk OUT MA request return\n");
+			break;
+		}
+		/*
+		 * Gadget driver should transfer more data to
+		 * serve bulk IN transfer, then wait for more requests.
+		 */
+		if (dir_in && (req->req.actual % ep->dev_ep->maxpacket == 0) &&
+		    (tx_state->rem_size - ep->actual_length > 0)
+		    && !req->req.zero) {
+			if (list_empty(ep->usb_req_list)) {
+				maudc_dbg(udc, "bulk IN: gadget request queue"
+					" is empty - waiting . . .\n");
+				while (list_empty(ep->usb_req_list))
+					msleep(1);
+			}
+			goto loop_request_queue;
+		}
+		/*
+		 * Doesn't copy all data in MA USB bulk OUT request.
+		 * Wait for additional gadget requests
+		 * to serve this MA USB bulk OUT request.
+		 */
+		if (!dir_in && (host_len > length)) {
+			if (list_empty(ep->usb_req_list)) {
+				maudc_dbg(udc, "bulk OUT: gadget request"
+					" is queue empty - waiting . . .\n");
+				while (list_empty(ep->usb_req_list))
+					msleep(1);
+			}
+			goto loop_request_queue;
+		}
+	}
+
+	return ep->actual_length;
+}
+
+
+/*------------------------- gadget operations -------------------------*/
+
+/**
+ * Handles control request to get device status.
+ */
+static int get_gadget_status(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc)
+{
+	int			ret = 0;
+	char			*buf;
+	unsigned int		address = le16_to_cpu(ctrlreq->wIndex);
+	struct usb_ep		*usb_ep = get_ep(udc, address);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(usb_ep,
+					udc->mausb_dev);
+
+	if (!ma_ep) {
+		maudc_err(udc, "%s: cannot find endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	buf = (char *)ma_ep->buffer;
+
+	maudc_dbg(udc, "%s: responding to request type %i\n",
+			__func__, ctrlreq->bRequestType);
+
+	/* requesting device status */
+	switch (ctrlreq->bRequestType) {
+	case DEV_IN_REQ:
+		buf[0] = udc->dev_status;
+		ma_ep->actual_length = 1;
+		break;
+
+	/* requesting an endpoint status */
+	case EP_IN_REQ:
+		buf[0] = ma_ep->halted;
+		ma_ep->actual_length = 1;
+		break;
+
+	/* requesting interface status */
+	case INTF_IN_REQ:
+		buf[0] = 0;
+		break;
+
+	default:
+		maudc_dbg(udc, "%s: invalid request type %i\n",
+			__func__, ctrlreq->bRequestType);
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Handles control request to set a gadget device feature.
+ */
+static int set_or_clear_gadget_feature(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc, int set)
+{
+	int			ret = 0;
+	unsigned int		address = le16_to_cpu(ctrlreq->wIndex);
+	struct usb_ep		*usb_ep = get_ep(udc, address);
+	struct mausb_host_ep	*ma_ep  = mausb_find_ep_dev(usb_ep,
+					udc->mausb_dev);
+
+	if (ctrlreq->bRequestType == EP_REQ) {
+
+		if (!ma_ep)
+			ret = -EINVAL;
+		else if (ma_ep->dev_ep->name == udc->gadget.ep0->name) {
+			maudc_err(udc, "%s: cannot halt ep0!\n", __func__);
+			ret = -EINVAL;
+		} else {
+			ma_ep->halted = set;
+			maudc_dbg(udc, "%s: %s halt %s\n", __func__,
+				ma_ep->dev_ep->name, set ? "set" : "cleared");
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Handles incoming management packets. Used to pass an MA USB management
+ * packet to the device.
+ */
+static int maudc_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context)
+{
+	int			ret;
+	struct mausb_pkt	*pkt;
+	struct mausb_udc	*udc  = platform_get_drvdata(&udc_pdev);
+	struct mausb_mgmt	*mgmt;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		maudc_err(udc, "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	mgmt = (struct mausb_mgmt *) context;
+
+	pkt = mausb_pkt_from_ms_pkt(ms_pkt,
+			udc->ma_dev.ms_driver->ops->pkt_destructor, GFP_ATOMIC);
+
+	maudc_dbg(udc, "%s: received %s packet\n", __func__,
+		mausb_type_to_string(pkt->common->pkt_type));
+
+	ret = mausb_rx_mgmt(pkt, mgmt);
+
+	return ret;
+}
+
+/**
+ * Suspends gadget..Called when a MAUSBDeviceSleepReq management packet is
+ * received.
+ */
+static void mausb_device_suspend(void)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver)
+		udc->driver->suspend(&udc->gadget);
+}
+
+/**
+ * Resumes gadget. Called by mausb_bus_resume in hcd to resume a connected
+ * device.
+ */
+static void mausb_device_resume(void)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver)
+		udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * Manages USB device connection to host. Called for connect and disconnect
+ * events.
+ */
+static int mausb_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mausb_udc *udc = gadget_to_udc(gadget);
+
+	udc->usb_ep[0].dev_ep.maxpacket = 64;
+	udc->gadget.speed = udc->driver->max_speed;
+	udc->pullup = is_on;
+
+	return 0;
+}
+
+/**
+ * Assigns an MA USB ep handle to the given endpoint.
+ */
+static void maudc_assign_ep_handle(struct mausb_host_ep *ma_ep,
+		struct usb_endpoint_descriptor *ep_des)
+{
+	struct mausb_ep_handle *handle = &ma_ep->ep_handle;
+
+	handle->dir = usb_endpoint_dir_in(ep_des) ? 1 : 0;
+	handle->ep_num = usb_endpoint_num(ep_des);
+	handle->dev_addr = MAUDC_DEV_ADDR;
+	handle->bus_num = MAUSB_VIRTUAL_BUS_NUM;
+
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_ACTIVE;
+}
+
+/**
+ * Adds a media-agnostic endpoint datastructure to the UDC for the given
+ * endpoint.
+ */
+static int maudc_add_ma_ep(struct usb_endpoint_descriptor *ep_des,
+		struct mausb_dev *mausb_dev, struct mausb_host_ep **mausb_ep)
+{
+	int			ret = -EINVAL;
+	struct mausb_host_ep	*ma_ep;
+	struct mausb_ms_drv	*drv = mausb_dev->ma_dev->ms_driver;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	struct usb_ep		*usb_ep = get_ep(udc, ep_des->bEndpointAddress);
+	unsigned long		irq_flags;
+	int (*transfer_pkt)(struct ms_pkt *pkt, void *context);
+
+	if (USB_ENDPOINT_XFER_CONTROL == usb_endpoint_type(ep_des)) {
+
+		maudc_dbg(udc, "%s: adding control endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_control;
+
+	} else if (usb_endpoint_dir_in(ep_des)) {
+		maudc_dbg(udc, "%s: adding IN endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_IN;
+
+	} else if (usb_endpoint_dir_out(ep_des)) {
+		maudc_dbg(udc, "%s: adding OUT endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_OUT;
+
+	} else {
+		maudc_dbg(udc, "%s: unknown endpoint type\n", __func__);
+		return -EINVAL;
+	}
+
+	mausb_internal_add_ep(mausb_dev, NULL, usb_ep, &ma_ep,
+		&device_transfer_timeout, GFP_ATOMIC);
+
+	if (NULL == ma_ep)
+		return -ENOMEM;
+
+	maudc_dbg(udc, "%s: added endpoint at 0x%p\n", __func__, ma_ep);
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	maudc_assign_ep_handle(ma_ep, ep_des);
+	ret = mausb_add_data_channel(drv, ma_ep, transfer_pkt);
+
+	ma_ep->gadget = mausb_dev->gadget;
+
+	/*
+	 * Note: The UDC uses a single MA URB to track the transfer
+	 * State variables for the active transfer.
+	 */
+	ma_ep->active_transfer = mausb_alloc_maurb(ma_ep, GFP_ATOMIC);
+
+	if (NULL != mausb_ep)
+		*mausb_ep = ma_ep;
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return ret;
+}
+
+/**
+ * Registers a media specific driver with the media agnostic driver.
+ */
+struct mausb_ma_drv *maudc_register_ms_driver(struct mausb_ms_drv *drv)
+{
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&udc->udc_lock, irq_flags);
+	udc->ma_dev.ms_driver = drv;
+	spin_unlock_irqrestore(&udc->udc_lock, irq_flags);
+
+	/* open the management channel */
+	maudc_dbg(udc, "%s: adding Managment channel...\n", __func__);
+	mausb_add_mgmt_channel(&udc->ma_dev.mgmt, drv,
+		&maudc_transfer_mgmt_packet, &mausb_mgmt_pkt_sent);
+
+	return &udc->ma_dev.ma_drv;
+}
+EXPORT_SYMBOL(maudc_register_ms_driver);
+
+int check_for_device(int dont_use)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver != NULL)
+		return 1;
+
+	return 0;
+}
+
+static int mausb_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct mausb_udc	*udc = gadget_to_udc(gadget);
+
+	maudc_dbg(udc, "%s: binding gadget '%s' driver\n",
+		__func__, driver->driver.name);
+
+	udc->driver = driver;
+
+	return 0;
+}
+
+static int mausb_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct mausb_udc	*udc = gadget_to_udc(gadget);
+
+	maudc_dbg(udc, "%s: stopping udc\n", __func__);
+
+	udc->driver = NULL;
+
+	return 0;
+}
+
+/**
+ * API to UDC operations that do not involve endpoints or i/o.
+ */
+static struct usb_gadget_ops mudc_ops = {
+	.pullup = &mausb_udc_pullup,
+	.udc_start = &mausb_udc_start,
+	.udc_stop = &mausb_udc_stop
+};
+
+/**
+ * Appends a Capabilities Descriptor to the end of a CapResp packet.
+ *
+ * @resp:	     CapResp to that will carry descriptor.
+ * @type:	     Descriptor type to add.
+ *		     Note: make sure to use values from MA USB Spec, Table 14.
+ * @offset:          Total length of other Device Capability Descriptors
+ *		     in resp.
+ *
+ * Returns length of added descriptor.
+ */
+static int add_cap_desc(struct mausb_mgmt_pkt *resp, int type, int offset)
+{
+	int			ret = 0;
+	int			ttl_offset;
+	struct			mausb_dev_cap_desc *desc;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+
+	ttl_offset = MAUSB_PKT_HEADER_SIZE +
+			sizeof(struct mausb_CapResp_flds) + offset;
+	desc = cap_desc_ptr_increment(resp, ttl_offset);
+
+	switch (type) {
+	case MAUSB_DEV_CAP_SPEED:
+		desc->length = MAUSB_DEV_CAP_SPEED_LENGTH;
+		desc->cap_type = MAUSB_DEV_CAP_SPEED;
+		desc->speed.speed = MAUSB_DEV_CAP_SPEED_SUPER;
+		/* TODO: assign speed fields meaningful values */
+		desc->speed.lse = 1;
+		desc->speed.st = 2;
+		desc->speed.lane_count = 3;
+		desc->speed.link_protocol = 3;
+		desc->speed.lsm = 234;
+		ret = desc->length;
+		break;
+	case MAUSB_DEV_CAP_POUT:
+		break;
+	case MAUSB_DEV_CAP_ISO:
+		break;
+	case MAUSB_DEV_CAP_SYNC:
+		break;
+	case MAUSB_DEV_CAP_CONT_ID:
+		break;
+	case MAUSB_DEV_CAP_LINK_SLEEP:
+		desc->length = MAUSB_DEV_CAP_LINK_SLEEP_LENGTH;
+		desc->cap_type = MAUSB_DEV_CAP_LINK_SLEEP;
+		desc->link_sleep.link_sleep_cap = 0;
+		ret = desc->length;
+		break;
+	default:
+		maudc_err(udc, "%s: invalid Device Capability Type %i\n",
+			__func__, type);
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Finds an MA USB endpoint descriptor inside of an endpoint handle response.
+ */
+static void maudc_fill_ma_ep_desc(struct mausb_ep_des *ma_ep_des,
+		struct usb_endpoint_descriptor *ep_des,
+		struct mausb_host_ep *ma_ep)
+{
+	ma_ep_des->ep_handle.handle = ma_ep->ep_handle.handle;
+	ma_ep_des->dir = usb_endpoint_dir_in(ep_des) ? 1 : 0;
+	ma_ep_des->iso = usb_endpoint_xfer_isoc(ep_des) ? 1 : 0;
+	ma_ep_des->l_man = 0;
+	ma_ep_des->valid = 0;
+	ma_ep_des->rsvd_0 = 0;
+
+	if ((usb_endpoint_dir_out(ep_des) && !usb_endpoint_xfer_isoc(ep_des))
+			|| usb_endpoint_xfer_control(ep_des)) {
+		ma_ep_des->ccu = 1;
+	} else
+		ma_ep_des->ccu = 0;
+
+	ma_ep_des->rsvd_1 = 0;
+
+	if (usb_endpoint_dir_out(ep_des) || usb_endpoint_xfer_control(ep_des))
+		ma_ep_des->buffer_size = ma_ep->state.rx_buf_size;
+	else
+		ma_ep_des->buffer_size = 0;
+
+	if (usb_endpoint_xfer_isoc(ep_des)) {
+		/* TODO: iso transfers */
+		/* ma_ep_des->iso_prog_dly = 0; */
+		/* ma_ep_des->iso_resp_dly = 0; */
+	} else {
+		ma_ep_des->iso_prog_dly = 0;
+		ma_ep_des->iso_resp_dly = 0;
+	}
+}
+
+/**
+ * Handles incoming EPHandleReq packets and fills EPHandleResp fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_req(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleReq_flds *req,
+		struct mausb_EPHandleResp_flds *resp)
+{
+	int				i;
+	enum mausb_pkt_status		status = UNSUCCESSFUL;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct usb_endpoint_descriptor	*ep_des;
+	struct usb_ep			*usb_ep;
+	struct mausb_host_ep		*ma_ep;
+
+	resp->num_ep_des = req->num_ep_des;
+
+	/* TODO: Sanity check; make sure we dont look past end of packet */
+	for (i = 0; i < req->num_ep_des; ++i) {
+
+		ep_des = mausb_ep_handle_req_get_ep_des(req, i);
+
+		if (NULL != ep_des) {
+
+			ma_ep = mausb_find_ep_by_address(
+				ep_des->bEndpointAddress, mausb_dev);
+
+			if (NULL != ma_ep) {
+				maudc_warn(udc, "%s: endpoint already exists"
+					"  resetting . . .\n", __func__);
+				mausb_internal_drop_ep(ma_ep);
+			}
+
+			maudc_add_ma_ep(ep_des, mausb_dev, &ma_ep);
+
+			if (NULL == ma_ep) {
+				maudc_err(udc, "%s: failed to add endpoint"
+					" for entry %i\n", __func__, i);
+			}
+
+			maudc_fill_ma_ep_desc(&resp->ep_des[i], ep_des, ma_ep);
+
+			usb_ep = get_ep(udc, ep_des->bEndpointAddress);
+
+			if (NULL != usb_ep)
+				mausb_link_ma_ep_to_usb_ep(ma_ep, usb_ep);
+
+			/* Per spec, if at least 1 endpoint assignment
+			 * is sucessful, the packet returns success.
+			 */
+			status = SUCCESS;
+		}
+	}
+
+	return status;
+}
+
+/**
+ * Handles incoming EPHandleDeleteReq packets and fills EPHandleDeleteResp
+ * fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_del_req(
+		struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleDelete_flds *req,
+		struct mausb_EPHandleDelete_flds *resp)
+{
+	int				i;
+	int				ret = 0;
+	enum mausb_pkt_status		status = UNSUCCESSFUL;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep		*ma_ep = NULL;
+	struct mausb_ep_handle		*req_handle;
+
+	resp->num_ep = 0;
+
+	/* TODO: Sanity check; make sure we dont look past end of packet */
+	for (i = 0; i < req->num_ep; ++i) {
+		req_handle = &req->ep_handle[i];
+
+		ma_ep = mausb_find_ep_by_handle(req_handle, mausb_dev);
+
+		ret = mausb_internal_drop_ep(ma_ep);
+
+		if (0 <= ret) {
+			/*
+			 * per spec, the packet returns sucess if it can
+			 * delete at least 1 endpoint
+			 */
+			status = SUCCESS;
+
+		} else {
+			resp->ep_handle[resp->num_ep].handle
+						= req_handle->handle;
+			resp->num_ep++;
+
+			maudc_err(udc, "%s: could not delete endpoint with"
+				" handle %x\n", __func__, req_handle->handle);
+		}
+	}
+
+	return status;
+}
+
+/**
+ * Inactivate endpoints in EPInactivateReq packet and fill
+ * EPInactivateResp fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_inactivate(
+		struct mausb_EPInactivateReq_flds *req,
+		struct mausb_EPInactivateResp_flds *resp,
+		struct mausb_dev *dev)
+{
+	int			i = 0;
+	int			failures = 0;
+	enum			mausb_pkt_status status = SUCCESS;
+	struct mausb_host_ep	*ma_ep = NULL;
+	struct mausb_ep_handle	*req_handle;
+
+	for (i = 0; i < req->num_ep_handles; ++i) {
+		req_handle = &req->ep_handle[i];
+		ma_ep = mausb_find_ep_by_handle(req_handle, dev);
+
+		if (!ma_ep) {
+			resp->ep_handle[failures] = *req_handle;
+			status = UNSUCCESSFUL;
+			failures++;
+		} else
+			ma_ep->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+	}
+
+	resp->num_ep_with_error = failures;
+
+	return status;
+}
+
+/**
+ * This function handles management requests to the UDC. It parses the packet
+ * and makes the necessary function calls into the system.
+ *
+ * @req:	The incoming request to handle.
+ * @resp: 	The response packet to send out.
+ * @mgmt:	The MA USB management structure associated with transfer.
+ *
+ * Note: this function only fills the packet type, status and
+ * request-specific data-fields. The remainder of the fields are set by
+ * mausb_rx_mgmt_req.
+ */
+static int udc_mgmt_req_switch(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt)
+{
+	int			ret = -EINVAL;
+	int			desc_count = 0;
+	int			offset = 0;
+	struct ma_dev		*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_udc	*udc = mausb_ma_dev_to_udc(ma_dev);
+
+	/* always set the device handle */
+	req->common.dev_handle = udc->mausb_dev->dev_handle;
+
+	switch (req->common.pkt_type) {
+
+	case CapReq:
+		/* non-hub devices require a Speed Capability Descriptor */
+		ret = add_cap_desc(resp, MAUSB_DEV_CAP_SPEED, offset);
+		if (ret <= 0) {
+			maudc_err(udc, "%s: could not add speed capability "
+				"descriptor\n", __func__);
+		} else {
+			desc_count++;
+			offset += ret;
+		}
+
+		ret = add_cap_desc(resp, MAUSB_DEV_CAP_LINK_SLEEP, offset);
+		if (ret <= 0) {
+			maudc_err(udc, "%s; could not add link sleep"
+				 " capability descriptor\n", __func__);
+		} else {
+			desc_count++;
+			offset += ret;
+		}
+
+		/*
+		 * TODO: if want to add more device cap descriptors, this would
+		 * be a good place to do it.
+		 */
+
+		resp->common.pkt_type = CapResp;
+		resp->common.pkt_status = NO_ERROR;
+		resp->cap_resp.num_ep = CAP_MAX_EP_NUM;
+		resp->cap_resp.num_dev = CAP_MAX_DEV_NUM;
+		resp->cap_resp.num_stream = EP_MAX_STREAMS;
+		resp->cap_resp.dev_type = CAP_DEV_TYPE;
+		resp->cap_resp.desc_count = desc_count;
+		resp->cap_resp.desc_length = offset;
+		resp->cap_resp.max_tx_reqs = CAP_MAX_TX_REQS;
+		resp->cap_resp.max_mgmt_reqs = CAP_MAX_MGMT_REQS;
+
+		ret = 0;
+		break;
+	case USBDevHandleReq:
+		udc->mausb_dev->dev_handle = MAUDC_DEV_HANDLE;
+
+		resp->common.pkt_type     = USBDevHandleResp;
+		resp->common.pkt_status   = NO_ERROR;
+		resp->usb_dev_handle_resp = MAUDC_DEV_HANDLE;
+
+		ret = 0;
+		break;
+	case EPHandleReq:
+		resp->common.pkt_type   = EPHandleResp;
+		resp->usb_dev_handle_resp = udc->mausb_dev->dev_handle;
+		resp->common.pkt_status = maudc_handle_ep_req(udc->mausb_dev,
+			&req->ep_handle_req, &resp->ep_handle_resp);
+		ret = 0;
+		break;
+	case EPActivateReq:
+		break;
+	case EPInactivateReq:
+		resp->common.pkt_type   = EPInactivateResp;
+		resp->common.pkt_status = maudc_handle_ep_inactivate(
+						&req->ep_inactivate_req,
+						&resp->ep_inactivate_resp,
+						udc->mausb_dev);
+		ret = 0;
+		break;
+	case EPResetReq:
+		break;
+	case EPClearTransferReq:
+		break;
+	case EPHandleDeleteReq:
+		resp->common.pkt_type   = EPHandleDeleteResp;
+
+		resp->common.pkt_status = maudc_handle_ep_del_req(
+			udc->mausb_dev, &req->ep_handle_delete,
+					&resp->ep_handle_delete);
+		ret = 0;
+		break;
+	case DevResetReq:
+		resp->common.pkt_type   = DevResetResp;
+
+		ma_dev->ma_dev_addr = req->common.ma_dev_addr;
+		ma_dev->mass_id = req->common.mass_id;
+
+		ret = 0;
+
+		if (0 == ret) {
+			resp->common.pkt_status = NO_ERROR;
+		} else {
+			resp->common.pkt_status =
+				mausb_errno_to_ma_status(ret);
+		}
+		break;
+	case ModifyEP0Req:
+		resp->common.pkt_type   = ModifyEP0Resp;
+		resp->common.pkt_status = SUCCESS;
+
+		/*
+		 * TODO: fix so to spec - for now we don't track USB device
+		 * state and can't do proper checks.
+		 */
+		if (req->modify_ep0_req.ep_handle.dev_addr == 0) {
+			/* && USB device is in addressed state) { */
+			resp->modify_ep0_resp.ep_handle.handle =
+				req->modify_ep0_req.ep_handle.handle
+					| (MAUDC_DEV_ADDR << 5);
+		} else {
+			resp->modify_ep0_resp.ep_handle.handle = 0;
+		}
+
+		ret = 0;
+		break;
+	case SetUSBDevAddrReq:
+		resp->common.pkt_type   = SetUSBDevAddrResp;
+		resp->common.pkt_status = NO_ERROR;
+		udc->mausb_dev->dev_address = MAUDC_DEV_ADDR;
+
+		resp->set_dev_addr_resp.dev_addr = udc->mausb_dev->dev_address;
+		ret = 0;
+		break;
+	case UpdateDevReq:
+		break;
+	case USBDevDisconnectReq:
+		resp->common.pkt_type   = USBDevDisconnectResp;
+		resp->common.dev_handle	= req->common.dev_handle;
+		resp->common.pkt_status = NO_ERROR;
+		ret = 0;
+		break;
+	case DevDisconnectReq:
+		resp->common.pkt_type   = DevDisconnectResp;
+		resp->common.dev_handle	= 0;
+		resp->common.pkt_status = NO_ERROR;
+		ret = 0;
+		break;
+	case SleepReq:
+		resp->common.pkt_type   = SleepResp;
+		resp->common.pkt_status = NO_ERROR;
+		mausb_device_suspend();
+		ret = 0;
+		break;
+	case WakeReq:
+		resp->common.pkt_type   = WakeResp;
+		resp->common.pkt_status = NO_ERROR;
+		mausb_device_resume();
+		ret = 0;
+		break;
+	case PingReq:
+		break;
+	case SyncReq:
+		break;
+	case CancelTransferReq:
+		resp->common.pkt_type   = CancelTransferResp;
+		resp->common.pkt_status = NO_ERROR;
+		resp->cancel_transfer_resp.ep_handle =
+				req->cancel_transfer_req.ep_handle;
+		resp->cancel_transfer_resp.stream_id =
+				req->cancel_transfer_req.stream_id;
+		resp->cancel_transfer_resp.req_id =
+				req->cancel_transfer_req.req_id;
+		/* TODO: cancel transfer and set fields below accordingly */
+		resp->cancel_transfer_resp.cancel_status = 1;
+		resp->cancel_transfer_resp.deliv_seq_num = 0;
+		resp->cancel_transfer_resp.deliv_byte_offset = 0;
+		ret = 0;
+		break;
+	case EPOpenStreamReq:
+		break;
+	case EPCloseStreamReq:
+		break;
+	case USBDevResetReq:
+		break;
+	case VendorSpecificReq:
+		break;
+
+	/* Invalid packet type */
+	default:
+		maudc_err(udc, "%s: invalid packet type\n", __func__);
+		ret = -EBADMSG;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * MA USB ep0 endpoint descriptor for a super speed endpoint
+ * per spec section 7.3.2.2.
+ */
+static struct usb_endpoint_descriptor mausb_ep0_desc = {
+
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0x00,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = 512,
+	.bInterval = 0
+};
+
+/**
+ * UDC probe function
+ */
+int mausb_udc_probe(struct platform_device *pdev)
+{
+	int				ret = 0;
+	int				i;
+	struct mausb_udc		*udc;
+	struct usb_ep			*usb_ep;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	udc->udc_lock = __SPIN_LOCK_UNLOCKED(udc->udc_lock);
+	/* initialize gadget structure */
+	udc->gadget.name = UDC_NAME;
+	udc->gadget.ops = &mudc_ops;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed = USB_SPEED_SUPER;
+	udc->gadget.dev.parent = &pdev->dev;
+
+	/* set head for list of gadget endpoints   */
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	/* initalize the ma_dev structure */
+	mausb_init_ma_device(&udc->ma_dev, 0, 0,
+		NULL, udc, &udc_mgmt_req_switch, &check_for_device);
+
+	udc->mausb_dev = mausb_internal_alloc_dev(&udc->ma_dev, NULL,
+		&udc->gadget);
+
+	for (i = 0; i < MAUDC_MAX_NUM_EP; i++) {
+		usb_ep = &udc->usb_ep[i].dev_ep;
+
+		usb_ep->name = ep_name[i];
+		usb_ep->ops = &mausb_ep_ops;
+		usb_ep->maxpacket = EP_MAX_PACKET;
+		usb_ep->max_streams = EP_MAX_STREAMS;
+
+		list_add_tail(&usb_ep->ep_list, &udc->gadget.ep_list);
+
+		INIT_LIST_HEAD(&udc->usb_ep[i].usb_req_list);
+	}
+
+	/* give gadget driver ep0 then remove from list*/
+	udc->usb_ep[0].dev_ep.desc = &mausb_ep0_desc;
+	udc->gadget.ep0 = &udc->usb_ep[0].dev_ep;
+	list_del_init(&udc->usb_ep[0].dev_ep.ep_list);
+
+	/* add a new gadget to the udc class driver list */
+	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "%s: could not add gadget UDC, error %d\n",
+			__func__, ret);
+	} else
+		platform_set_drvdata(pdev, udc);
+
+	return ret;
+}
+
+int mausb_udc_remove(struct platform_device *pdev)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: removing udc\n", __func__);
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	return 0;
+}
+
+int mausb_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: suspending udc\n", __func__);
+
+	udc->suspended = 1;
+
+	return 0;
+}
+
+int mausb_udc_resume(struct platform_device *pdev)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: resuming udc\n", __func__);
+
+	udc->suspended = 0;
+
+	return 0;
+}
+
+/**
+ * platform structures for USB Device Controller (UDC)
+ */
+static struct platform_device udc_pdev = {
+	.name = UDC_NAME,
+	.id = 0
+};
+
+static struct platform_driver udc_driver = {
+	.probe = mausb_udc_probe,
+	.remove = mausb_udc_remove,
+	.suspend = mausb_udc_suspend,
+	.resume = mausb_udc_resume,
+	.driver = {
+		.name = UDC_NAME,
+		.owner = THIS_MODULE
+	}
+};
+
+/**
+ * initialization function
+ */
+static int mausb_udc_init(void)
+{
+	int ret;
+
+	printk(KERN_DEBUG "loading MA USB UDC . . .\n");
+
+	/* register UDC driver */
+	ret = platform_driver_register(&udc_driver);
+	if (ret < 0) {
+		printk(KERN_DEBUG "failed to register UDC driver - "
+			"error # %d\n", ret);
+	} else {
+		/* register UDC device */
+		ret = platform_device_register(&udc_pdev);
+		if (ret < 0) {
+			printk(KERN_DEBUG "failed to register UDC device - "
+				"error # %d\n", ret);
+			platform_driver_unregister(&udc_driver);
+
+		} else {
+			/* direct the release function (for exiting) */
+			udc_pdev.dev.release = &udc_dev_release;
+		}
+	}
+
+	return ret;
+}
+module_init(mausb_udc_init);
+
+/**
+ * exit function
+ */
+static void mausb_udc_exit(void)
+{
+	/* deregister UDC device */
+	platform_device_unregister(&udc_pdev);
+
+	/* deregister UDC driver */
+	platform_driver_unregister(&udc_driver);
+
+}
+module_exit(mausb_udc_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_udc");
diff --git a/drivers/staging/mausb/drivers/mausb_udc.h b/drivers/staging/mausb/drivers/mausb_udc.h
new file mode 100644
index 0000000..b900b2d
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_udc.h
@@ -0,0 +1,147 @@
+/* name:	mausb_udc.h
+ * description:	header file for mausb_udc.h
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.o.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_UDC_H
+#define __MAUSB_UDC_H
+
+#include <linux/timer.h>
+#include <linux/usb/gadget.h>
+#include "mausb_state.h"
+#include "mausb_pkt.h"
+#include "mausb_msapi.h"
+#include "mausb_mem.h" /* for mgmt structure */
+#include "mausb_const.h"
+
+#define UDC_NAME "mausb udc"
+#define MAUDC_MAX_NUM_EP 3
+#define EP_MAX_PACKET  64  /* max number of packets ep can handle */
+#define EP_MAX_STREAMS 16 /* max number of streams ep can handle */
+#define REQ_BUF_SIZE   64
+#define CAP_MAX_EP_NUM	3 /* max number of endpoints state can be tracked for */
+#define CAP_MAX_DEV_NUM 1 /* max number of devices that can be managed
+			   * note this is 1 because only hubs can have >1 */
+#define CAP_DEV_TYPE	0 /* device type: 0 = not an MA USB hub
+			   *		  1 = USB 2.0 hub
+			   *		  2 = USB 3.1 hub */
+#define CAP_MAX_TX_REQS 0x01FF /* max number of outstanding transfer requests
+				* device can track - arbitrarily chosen */
+#define CAP_MAX_MGMT_REQS 0x01F /* max number of outstanding management requests
+				 * device can track - arbitrarily chosen */
+
+#define MAUDC_DEV_HANDLE 0x1359 /* MA Device handle for the USB device */
+
+#define MAUDC_DEV_ADDR 0x7D /* USB Device address for the USB device */
+			/* Note: MAUDC_DEV_ADDR is arbitrary */
+
+#define MAUDC_BUS_NUM 0xD /* Bus number to be used in the endpoint handle */
+
+#define MAUSB_GADGET_TIMEOUT 3	/* time out for gadget driver enqueue request */
+
+#define maudc_info(udc, fmt, args...) \
+	dev_info(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_dbg(udc, fmt, args...) \
+	dev_dbg(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_warn(udc, fmt, args...) \
+	dev_warn(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_err(udc, fmt, args...) \
+	dev_err(udc->gadget.dev.parent , fmt , ## args)
+
+/* function declarations */
+void udc_dev_release(struct device *dev);
+int mausb_udc_probe(struct platform_device *pdev);
+int mausb_udc_remove(struct platform_device *pdev);
+int mausb_udc_suspend(struct platform_device *pdev, pm_message_t state);
+int mausb_udc_resume(struct platform_device *pdev);
+int check_for_device(int dont_use);
+
+
+/* function declarations */
+int do_ma_transfer(struct mausb_host_ep *ep, struct mausb_pkt *tx_req,
+		bool dir_in);
+/**
+ * UDC structure
+ *
+ * The UDC structure holds all of the per-device data. This includes both the
+ * media agnostic device data as well as the USB device data. The USB device
+ * connected to the UDC is considered an integrated USB Device.
+ *
+ * @mausb_gadget_ep:	An array of all the endpoints for this device.
+ * @usb_gadget:		The device's gadget structure.
+ * @usb_gadget_driver:	the device's driver.
+ * @ma_dev:		The media agnostic device structure. Holds all the
+ *			data common to all media agnostic devices.
+ * @mausb_dev:		Holds media agnostic data that represents a USB device.
+ * @ms_driver:		The MAUSB driver's interface with the media specific
+ *			driver.
+ * @udc_lock:		The 'big' lock. Used to protect this structure's data
+ *            		from concurrent access.
+ * @dev_status:		Holds USB device status.
+ * @suspended:		1 when UDC is suspended, otherwise 0.
+ * @pullup:		1 when a USB device is connecting to UDC, otherwise 0.
+ */
+struct mausb_udc {
+	struct mausb_gadget_ep		usb_ep[MAUDC_MAX_NUM_EP];
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	struct ma_dev			ma_dev;
+	struct mausb_dev		*mausb_dev;
+	spinlock_t			udc_lock;
+	u16				dev_status;
+	unsigned			suspended:1;
+	unsigned			pullup:1;
+};
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 07/10] added media agnostic (MA) USB management packet handling
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (5 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

The Media Agnostic USB Specification outlines a number of managment
packet types for management and control functions. Each function is
initiated with a particular type of managment request packet and
completed with the corresponding management response packet. This
is where we fill the fields for outgoing management packets and parse
and handle incoming management packets.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_mgmt.c | 888 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_mgmt.h |  90 +++
 2 files changed, 978 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_mgmt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mgmt.h

diff --git a/drivers/staging/mausb/drivers/mausb_mgmt.c b/drivers/staging/mausb/drivers/mausb_mgmt.c
new file mode 100755
index 0000000..7301ae3
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mgmt.c
@@ -0,0 +1,888 @@
+/* name:	mausb_mgmt.c
+ * description: Handles management packet operations common to both
+ *              hosts and devices. This includes parsing incoming packets,
+ *              as well as creating outgoing packets.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#include "mausb_pkt.h"
+#include "mausb_mgmt.h"
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+#include "mausb_const.h"
+
+/**
+ * Returns the ma_dev structure for a given device.
+ */
+struct ma_dev *mausb_mgmt_to_ma_dev(struct mausb_mgmt *mgmt)
+{
+	return container_of(mgmt, struct ma_dev, mgmt);
+}
+EXPORT_SYMBOL(mausb_mgmt_to_ma_dev);
+
+/**
+ * Opens a connection to the Media Specific driver to pass management packets
+ * to a particular MA device.
+ *
+ * The caller should be holding the lock protecting the MA device's data.
+ *
+ * Returns 0 on success, or a negative errno on failure.
+ *
+ * @mgmt:		The struct for the management channel to the MA device.
+ *              	after this function
+ * @drv:		The specific medium we are communicating with
+ * @transfer_pkt:	A pointer to the function that should be called by the
+ *                    	MS driver to pass incoming management packets to the
+ *                    	MA driver.
+ * @pkt_sent:		Completion callback for outgoing management packets.
+ *			This function will be called by the MS driver once a
+ *			packet has been sent to the medium to indicate that
+ *			it is done with the packet. Note: the completion
+ *			callback can be disabled by setting this to NULL.
+ */
+int mausb_add_mgmt_channel(struct mausb_mgmt *mgmt, struct mausb_ms_drv *drv,
+		int  (*transfer_pkt)(struct ms_pkt *pkt, void *context),
+		void (*pkt_sent)(struct ms_pkt *pkt))
+{
+	int				ret = 0;
+	struct mausb_transfer_pair	tx_pair;
+	unsigned long			irq_flags;
+
+	tx_pair.to_ma.transfer_packet = transfer_pkt;
+	tx_pair.pkt_sent = pkt_sent;
+	tx_pair.to_ma.context = mgmt;
+	tx_pair.handle = MAUSB_MGMT_HANDLE;
+
+	ret = drv->ops->add_transfer_pair(&tx_pair);
+
+	if (ret >= 0) {
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+		mgmt->tx_pair = tx_pair;
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_add_mgmt_channel);
+
+/**
+ * Fills the fields in an endpoint handle req.
+ *
+ * @dev:	The device struct that contains the endpoints to open.
+ * @req_flds:	The req_flds to fill.
+ *
+ * Note: this function can only be used on the host side.
+ */
+int mausb_fill_ep_handle_req_flds(struct mausb_dev *mausb_dev,
+		struct mausb_mgmt_pkt *req, bool add)
+{
+	int				   i = 0;
+	struct mausb_host_ep		   *ma_ep;
+	unsigned long			   irq_flags;
+	struct mausb_ss_ep_req		   *ss_ep_des;
+	struct mausb_ep_req		   *ep_des;
+	struct mausb_EPHandleReq_flds	   *req_flds = &req->ep_handle_req;
+	struct mausb_EPHandleDelete_flds   *del_flds = &req->ep_handle_delete;
+
+	req_flds->num_ep_des = 0;
+
+	if (USB_SPEED_SUPER == mausb_dev->dev->speed)
+		req_flds->size_ep_des = cpu_to_le32(MAUSB_SS_EP_REQ_SIZE);
+	else
+		req_flds->size_ep_des = cpu_to_le32(MAUSB_EP_REQ_SIZE);
+
+	/* for every endpoint */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+		/* if we need to add this endpoint */
+		if (add && (MAUSB_EP_HANDLE_UNASSIGNED
+					== ma_ep->ep_handle_state)) {
+
+			if (USB_SPEED_SUPER == mausb_dev->dev->speed &&
+				ma_ep->ep->desc.bEndpointAddress != 0x00) {
+				ss_ep_des = &req_flds->ss_ep_des[i];
+
+				memcpy(&ss_ep_des->ep_des,
+					&ma_ep->ep->desc,
+					USB_DT_ENDPOINT_SIZE);
+
+				memcpy(&ss_ep_des->ss_ep_comp_des,
+					&ma_ep->ep->ss_ep_comp,
+					USB_DT_SS_EP_COMP_SIZE);
+			} else {
+				ep_des = &req_flds->ep_des[i];
+
+				memcpy(&ep_des->ep_des,
+					&ma_ep->ep->desc,
+					USB_DT_ENDPOINT_SIZE);
+			}
+
+			if (ma_ep->ep->desc.bEndpointAddress == 0x00)
+				req_flds->size_ep_des = MAUSB_EP_REQ_SIZE;
+
+			i++;
+			req_flds->num_ep_des = i;
+
+		/* if we need to delete this endpoint */
+		} else if (!add &&
+			(MAUSB_EP_HANDLE_DELETED == ma_ep->ep_handle_state)) {
+
+			del_flds->ep_handle[i].handle =
+				cpu_to_le16(ma_ep->ep_handle.handle);
+
+			i++;
+			req_flds->num_ep_des = i;
+		}
+
+		spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	if (i <= 0)
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
+ * Looks for inactive endpoints and fills EPInactivateReq packet fields
+ * accordingly.
+ */
+int mausb_fill_ep_inactivate_req_flds(struct mausb_dev *mausb_dev,
+		struct mausb_mgmt_pkt *req)
+{
+	int				    i = 0;
+	struct mausb_host_ep		    *ma_ep;
+	unsigned long			    irq_flags;
+	struct mausb_EPInactivateReq_flds   *req_flds = &req->ep_inactivate_req;
+
+	/*
+	 * Grab any inactive endpoints. After EPInactivateReq is sent, inactive
+	 * endoints will be marked for deletion.
+	 */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+		/* If endpoint has been inactivated, include it in packet. */
+		if (ma_ep->ep_handle_state == MAUSB_EP_HANDLE_INACTIVE) {
+			req_flds->ep_handle[i] = ma_ep->ep_handle;
+			i++;
+			req_flds->num_ep_handles = i;
+			ma_ep->ep_handle_state = MAUSB_EP_HANDLE_DELETED;
+		}
+
+		spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	/*TODO: set suspend flag when needed */
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	return req_flds->num_ep_handles;
+}
+
+/**
+ * Transmits a mausb management packet req and awaits a resp
+ *
+ * Caller should be holding the lock in the mausb_mgmt structure.
+ *
+ * This function transmits a MA USB management request packet and waits for a
+ * response. If a response packet is received, this function will return
+ * 0 with valid data in the resp. If the request timed out, will return
+ * -ETIMEDOUT.
+ *
+ * Note: since the calling process sleeps, this function CANNOT be called
+ *       from an interrupt context.
+ *
+ * @req:	A pointer to the MA USB transferRequest packet to be sent.
+ * @resp:	A pointer to the MA USB transferResponse packet received.
+ * @ma_mgmt:	The Ma USB device's management structure.
+ */
+static int internal_mausb_tx_mgmt_req(struct mausb_pkt *req,
+		struct mausb_pkt **resp, struct mausb_mgmt *ma_mgmt)
+{
+	int				retries = 0;
+	int				rem_time = 0;
+	struct mausb_mgmt_req_list	*req_entry;
+	struct mausb_pkt_transfer	*transfer;
+	unsigned long			irq_flags = 0;
+
+	if (NULL == ma_mgmt->tx_pair.to_ms.transfer_packet)
+		return -EPIPE;
+	else
+		transfer = &ma_mgmt->tx_pair.to_ms;
+
+	req_entry = kzalloc(sizeof(struct mausb_mgmt_req_list), GFP_ATOMIC);
+	if (!req_entry)
+		return -ENOMEM;
+
+	req_entry->mgmt_req = req;
+	req_entry->mgmt_resp = NULL;
+	init_completion(&req_entry->resp_rcvd);
+	INIT_LIST_HEAD(&req_entry->req_list);
+
+	list_add_tail(&req_entry->req_list, &ma_mgmt->req_list);
+
+	req->common->length = cpu_to_le16(mausb_pkt_length(req));
+
+	ma_mgmt->token = (ma_mgmt->token % MAUSB_MGMT_MAX_TOKEN) + 1;
+	req->mgmt->token = ma_mgmt->token;
+
+	/* until we time out or complete */
+	for (retries = 0; (retries <= MAUSB_MGMT_TRANSFER_RETRIES) &&
+			(NULL == req_entry->mgmt_resp); retries++) {
+
+		/* if this is a retry */
+		if (retries > 0)
+			req->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+
+		spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+
+		mausb_pkt_fill_ms_pkt(req, GFP_ATOMIC);
+
+		mamgmt_dbg("%s: sending %s packet\n", __func__,
+			mausb_type_to_string(req->common->pkt_type));
+		transfer->transfer_packet(&req->pkt, transfer->context);
+
+		rem_time = wait_for_completion_interruptible_timeout(
+			&req_entry->resp_rcvd, MAUSB_MGMT_RT_DELAY);
+
+		spin_lock_irqsave(ma_mgmt->ma_dev_lock, irq_flags);
+	}
+
+	list_del(&req_entry->req_list);
+	*resp = req_entry->mgmt_resp;
+
+	kfree(req_entry);
+
+	if (rem_time == 0) /* if we timed out */
+		return -ETIMEDOUT;
+	else if (rem_time < 0) /* if an error happened */
+		return rem_time;
+	else /* return based on the status of the response */
+		return 0;
+}
+
+/**
+ * Accepts the EPHandleResp and EPHandleReq Fields and updates
+ * endpoint(s) state based on the Resp Fields.
+ */
+static int mausb_handle_ep_resp(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleReq_flds *req,
+		struct mausb_EPHandleResp_flds *resp)
+{
+	int				i;
+	int				ret = -EINVAL;
+	struct mausb_host_ep		*ma_ep;
+	struct usb_endpoint_descriptor	*ep_des;
+
+	if (le32_to_cpu(req->num_ep_des) != le32_to_cpu(resp->num_ep_des))
+		return -EINVAL;
+
+	for (i = 0; i < resp->num_ep_des; ++i) {
+
+		ep_des = mausb_ep_handle_req_get_ep_des(req, i);
+		if (NULL != ep_des) {
+
+			ma_ep = mausb_find_ep_by_desc(ep_des, mausb_dev);
+			if (ma_ep != NULL)
+				ret = mausb_update_ep(ma_ep, &resp->ep_des[i]);
+			else {
+				mamgmt_err("%s: could not find endpoint"
+				" for handle #%i (%x)\n", __func__, i,
+				le16_to_cpu(resp->ep_des[i].ep_handle.handle));
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Accepts the EPHandleDeleteReq and EPHandleDeleteResp Fields and updates
+ * the endpoint(s) state based on the Resp Fields.
+ */
+static int mausb_handle_ep_del_resp(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleDelete_flds *req,
+		struct mausb_EPHandleDelete_flds *resp)
+{
+	int ret			      = 0;
+	int			      i, j;
+	bool			      drop_failed;
+	struct mausb_host_ep	      *ma_ep;
+	struct mausb_ep_handle	      *req_handle;
+	struct mausb_ms_drv	      *ms_driver = mausb_dev->ma_dev->ms_driver;
+
+	/* for every endpoint in the req */
+	for (i = 0; i < req->num_ep; ++i) {
+
+		drop_failed = false;
+		req_handle = &req->ep_handle[i];
+
+		for (j = 0; j < le32_to_cpu(resp->num_ep); ++j) {
+			if (req_handle->handle ==
+				le16_to_cpu(resp->ep_handle[j].handle))
+
+				drop_failed = true;
+		}
+
+		if (false == drop_failed) {
+
+			ma_ep = mausb_find_ep_by_handle(req_handle, mausb_dev);
+
+			ret = ms_driver->ops->drop_transfer_pair(
+				ma_ep->ep_handle.handle,
+				ma_ep->tx_pair.to_ms.context);
+
+			if (0 <= ret) {
+				/* drop the endpoint locally */
+				ret = mausb_internal_drop_ep(ma_ep);
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Determines the speed to report in the USBDevHandleReq.
+ */
+static __u8 mausb_get_dev_speed(struct mausb_dev *dev)
+{
+	switch (dev->dev->speed) {
+	case USB_SPEED_LOW:
+		return MAUSB_LOW_SPEED;
+	case USB_SPEED_FULL:
+		return MAUSB_FULL_SPEED;
+	case USB_SPEED_HIGH:
+		return MAUSB_HIGH_SPEED;
+	case USB_SPEED_SUPER:
+		return MAUSB_SUPER_SPEED;
+	/* TODO: SUPER_SPEED_PLUS */
+	default:
+		return MAUSB_INVALID_SPEED;
+	}
+}
+
+/**
+ * Parses all descriptors for a given CapResp packet and stores data in
+ * corresponding device data structure.
+ *
+ * Returns number of descriptors read.
+ */
+int parse_cap_desc(struct mausb_pkt *resp, struct ma_dev *ma_dev)
+{
+	int			   ret = 0;
+	int			   offset = 0;
+	int			   desc_count = resp->mgmt->cap_resp.desc_count;
+	struct mausb_dev_cap_desc  *desc;
+
+	offset = MAUSB_PKT_HEADER_SIZE + sizeof(struct mausb_CapResp_flds);
+	desc = cap_desc_ptr_increment(resp->mgmt, offset);
+
+	if (resp->common->pkt_type != CapResp) {
+		mamgmt_err("%s: packet is type %i (not a CapResp)\n", __func__,
+			resp->common->pkt_type);
+		return -EINVAL;
+	}
+
+	while (desc_count) {
+		if (desc == NULL) {
+			mamgmt_err("%s: no descriptor to read\n", __func__);
+			return ret;
+		}
+
+		ret++;
+
+		switch (desc->cap_type) {
+		case MAUSB_DEV_CAP_SPEED:
+			ma_dev->speed = kzalloc(
+				sizeof(struct mausb_dev_cap_speed),
+				GFP_ATOMIC);
+			ma_dev->speed->speed = desc->speed.speed;
+			ma_dev->speed->lse = desc->speed.lse;
+			ma_dev->speed->st = desc->speed.st;
+			ma_dev->speed->lane_count =
+				desc->speed.lane_count;
+			ma_dev->speed->link_protocol =
+				desc->speed.link_protocol;
+			ma_dev->speed->lsm = desc->speed.lsm;
+			break;
+		case MAUSB_DEV_CAP_POUT:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_pout),
+				GFP_ATOMIC);
+			ma_dev->pout->elastic_buf_cap =
+				desc->pout.elastic_buf_cap;
+			ma_dev->pout->drop_notif =
+				desc->pout.drop_notif;
+			break;
+		case MAUSB_DEV_CAP_ISO:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_iso),
+				GFP_ATOMIC);
+			ma_dev->iso->iso_alignment =
+				desc->iso.iso_alignment;
+			break;
+		case MAUSB_DEV_CAP_SYNC:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_sync),
+				GFP_ATOMIC);
+			ma_dev->sync->media_time_avail =
+				desc->sync.media_time_avail;
+			ma_dev->sync->timestamp_req =
+				desc->sync.timestamp_req;
+			break;
+		case MAUSB_DEV_CAP_CONT_ID:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_cont_id),
+				GFP_ATOMIC);
+			ma_dev->cont_id->cont_id_upper =
+				desc->cont_id.cont_id_upper;
+			ma_dev->cont_id->cont_id_lower =
+				desc->cont_id.cont_id_lower;
+			break;
+		case MAUSB_DEV_CAP_LINK_SLEEP:
+			ma_dev->link_sleep = kzalloc(
+				sizeof(struct mausb_dev_cap_link_sleep),
+				GFP_ATOMIC);
+			ma_dev->link_sleep->link_sleep_cap =
+				desc->link_sleep.link_sleep_cap;
+			break;
+		default:
+			mamgmt_err("%s: unknown device capability descriptor"
+				" type %i\n", __func__, desc->cap_type);
+			ret--;
+			break;
+		}
+
+		desc_count--;
+		offset += desc->length;
+		desc = cap_desc_ptr_increment(resp->mgmt, offset);
+	}
+
+	return ret;
+}
+
+/**
+ * Transmits a management packet of the specified type for the given device.
+ *
+ * @type:	The type of MA USB management request packet being sent.
+ * @mgmt:	The management data we need to send the packet.
+ * @dev:	The device this packet is associated with. Set to NULL if
+ *	        there is no associated device (ex: for MAUSBDevReset).
+ * @host:	Set TRUE to indicate we are a host, set to FALSE if we are
+ *              a device.
+ */
+int mausb_tx_dev_mgmt_req(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host)
+{
+	return mausb_tx_dev_mgmt_req_ep(type, mgmt, dev, host, NULL);
+}
+EXPORT_SYMBOL(mausb_tx_dev_mgmt_req);
+
+/**
+ * Only necessary to call directly if you need to specify an EP, otherwise
+ * mausb_tx_dev_mgmt_req will work.
+ */
+int mausb_tx_dev_mgmt_req_ep(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host, struct mausb_host_ep *ma_ep)
+{
+	int			ret = 0;
+	struct mausb_pkt	*req;
+	struct mausb_pkt	*resp = NULL;
+	struct ma_dev		*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_dev	*hub;
+	unsigned long		irq_flags;
+
+	req = mausb_alloc_pkt(MAUSB_PKT_TYPE_MGMT, &ret, GFP_ATOMIC);
+	if (!req)
+		return -ENOMEM;
+
+	spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	req->common->ver_flags  |= MAUSB_VERSION_1_0;
+	req->common->pkt_type    = type;
+	if (NULL != dev)
+		req->common->dev_handle  = cpu_to_le16(dev->dev_handle);
+
+	req->common->ma_dev_addr = ma_dev->ma_dev_addr;
+	req->common->mass_id     = ma_dev->mass_id;
+	req->common->pkt_status  = NO_ERROR;
+
+	if (host)
+		req->common->ver_flags  |= MAUSB_PKT_FLAG_HOST;
+
+	switch (type) {
+	case CapReq:
+		req->mgmt->cap_req.max_mgmt_reqs = MAUSB_MGMT_MAX_TOKEN;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (0 <= ret) {
+			ma_dev->ma_cap.num_ep = resp->mgmt->cap_resp.num_ep;
+			ma_dev->ma_cap.num_dev = resp->mgmt->cap_resp.num_dev;
+			ma_dev->ma_cap.num_stream =
+					resp->mgmt->cap_resp.num_stream;
+			ma_dev->ma_cap.dev_type = resp->mgmt->cap_resp.dev_type;
+			ma_dev->ma_cap.max_tx_reqs =
+					resp->mgmt->cap_resp.max_tx_reqs;
+			ma_dev->ma_cap.max_mgmt_reqs =
+					resp->mgmt->cap_resp.max_mgmt_reqs;
+
+			/* look for descriptors */
+			if (resp->mgmt->cap_resp.desc_count > 0) {
+				ret = parse_cap_desc(resp, ma_dev);
+
+				if (ret != resp->mgmt->cap_resp.desc_count) {
+					mamgmt_err("%s: error reading"
+						" capability descriptors\n",
+						__func__);
+				}
+			}
+		}
+		break;
+
+	case EPHandleReq:
+		mausb_fill_ep_handle_req_flds(dev, req->mgmt, MAUSB_ADD);
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		if (0 <= ret) {
+			ret = mausb_handle_ep_resp(dev,
+				&req->mgmt->ep_handle_req,
+				&resp->mgmt->ep_handle_resp);
+		}
+		break;
+	case EPActivateReq:
+	case EPInactivateReq:
+		ret = mausb_fill_ep_inactivate_req_flds(dev, req->mgmt);
+		if (ret > 0)
+			ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case EPResetReq:
+	case EPClearTransferReq:
+		break;
+	case EPHandleDeleteReq:
+		mausb_fill_ep_handle_req_flds(dev, req->mgmt, MAUSB_DEL);
+
+		if (0 < le32_to_cpu(req->mgmt->ep_handle_delete.num_ep)) {
+			ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+			mausb_handle_ep_del_resp(dev,
+				&req->mgmt->ep_handle_delete,
+				&resp->mgmt->ep_handle_delete);
+		}
+		break;
+	case USBDevHandleReq:
+		req->mgmt->usb_dev_handle_req.dock_hub
+			= cpu_to_le16(mgmt->hub_dev_handle);
+		req->mgmt->usb_dev_handle_req.usb_rt_str
+			= cpu_to_le32(dev->dev->route);
+		req->mgmt->usb_dev_handle_req.speed =
+			cpu_to_le32(mausb_get_dev_speed(dev));
+		req->common->dev_handle = 0;
+
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+		hub = mausb_find_dev(ma_dev, dev->dev->parent, NULL, NULL);
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+		if (NULL != hub) {
+			/* This will work if the device is connected directly to
+			 * the dock, but not with a hub connected to the dock...
+			 * well... unless the hub in between is slower than high
+			 * speed. */
+			/* TODO: have the parent hub point to the proper hub for
+			 *       all conditions */
+			req->mgmt->usb_dev_handle_req.parent_hub =
+				hub->dev_handle;
+			req->mgmt->usb_dev_handle_req.parent_hub_port =
+				dev->dev->portnum;
+		} else {
+			/* parent_hub_port not set for SS */
+			mamgmt_dbg("%s: could not find parent hub at %p\n",
+				__func__, dev->dev->parent);
+		}
+
+		/* TODO: all the remaining fields */
+		req->mgmt->usb_dev_handle_req.mtt = 0;
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (resp && (NULL != dev))
+			dev->dev_handle =
+				le16_to_cpu(resp->mgmt->usb_dev_handle_resp);
+		break;
+
+	case DevResetReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case ModifyEP0Req:
+		if (NULL == ma_ep) {
+			mamgmt_err("%s: no ep0 for USB device at %p\n",
+				__func__, dev);
+		} else {
+			req->mgmt->modify_ep0_req.ep_handle = ma_ep->ep_handle;
+			req->mgmt->modify_ep0_req.max_pkt_size =
+				usb_endpoint_maxp(&ma_ep->ep->desc);
+		}
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		if (0 <= ret) {
+			if (SUCCESS == resp->common->pkt_status) {
+				if (resp->mgmt->modify_ep0_resp.ep_handle.handle) {
+					ma_ep->ep_handle = resp->mgmt->modify_ep0_resp.ep_handle;
+				}
+			} else
+				ret = -EIO;
+		}
+		break;
+	case SetUSBDevAddrReq:
+		/* TODO: verify timer value */
+		req->mgmt->set_dev_addr_req.resp_timeout =
+			cpu_to_le16(MAUSB_MGMT_RT_DELAY * (1000/HZ));
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (0 <= ret) {
+			if (SUCCESS == resp->common->pkt_status) {
+				dev->dev_address =
+					le32_to_cpu(
+					resp->mgmt->set_dev_addr_resp.dev_addr);
+			} else
+				ret = -EIO;
+		}
+		break;
+	case UpdateDevReq:
+		break;
+	case USBDevDisconnectReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case DevDisconnectReq:
+		req->common->dev_handle = 0;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case SleepReq:         /* fallthrough */
+	case WakeReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		/* not everyone supports power management yet */
+		/* if (SUCCESS != resp->common->pkt_status)
+			ret = -EBUSY; */
+		break;
+	case RemoteWakeReq:
+	case PingReq:
+	case DevInitDisconnectReq:
+	case SyncReq:
+		break;
+	case CancelTransferReq:
+		req->mgmt->cancel_transfer_req.ep_handle = ma_ep->ep_handle;
+		/* TODO: stream IDs (where applicable) */
+		req->mgmt->cancel_transfer_req.req_id =
+				ma_ep->state.active_request_id;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		/* TODO: handle Responses */
+		break;
+	case USBDevResetReq:
+	case VendorSpecificReq:
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (resp != NULL)
+		mausb_free_pkt(resp);
+
+	spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	mausb_free_pkt(req);
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_tx_dev_mgmt_req_ep);
+
+/**
+ * Parses an incoming management packet resp.
+ *
+ * This function parses an incoming response packet and connects it to
+ * its associated request.
+ *
+ * @resp:	A pointer to the MA USB management response packet received.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt_resp(struct mausb_pkt *resp, struct mausb_mgmt *ma_mgmt)
+{
+	struct mausb_mgmt_req_list	*ma_mgmt_req;
+	unsigned long			irq_flags;
+
+	spin_lock_irqsave(ma_mgmt->ma_dev_lock, irq_flags);
+
+	list_for_each_entry(ma_mgmt_req, &ma_mgmt->req_list, req_list) {
+
+		/* if we found the request that triggered this response */
+		if (ma_mgmt_req->mgmt_req->mgmt->token == resp->mgmt->token) {
+			ma_mgmt_req->mgmt_resp = resp;
+
+			complete_all(&ma_mgmt_req->resp_rcvd);
+			spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+			return 0;
+		}
+	}
+
+	/* response given was not requested */
+	spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+
+	mausb_free_pkt(resp);
+
+	return -EINVAL;
+}
+
+/**
+ * This function parses an incoming request packet and generates the
+ * appropriate response packet.
+ *
+ * @resp:	A pointer to the MA USB management request packet received.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt_req(struct mausb_pkt *req, struct mausb_mgmt *mgmt)
+{
+	int				ret;
+	struct mausb_pkt		*resp;
+	struct ma_dev			*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_pkt_transfer	*transfer = &mgmt->tx_pair.to_ms;
+	unsigned long			irq_flags;
+
+	resp = mausb_alloc_pkt(MAUSB_PKT_TYPE_MGMT, &ret, GFP_ATOMIC);
+	if (!resp)
+		return -ENOMEM;
+
+	spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	ret = mgmt->req_switch(req->mgmt, resp->mgmt, mgmt);
+
+	if (ret >= 0) {
+		/* set the values common to all response packets */
+		resp->common->ver_flags |= MAUSB_VERSION_1_0;
+		/* type set above */
+		resp->common->length      = cpu_to_le16(mausb_pkt_length(resp));
+		/* device handle set above */
+		resp->common->ma_dev_addr = ma_dev->ma_dev_addr;
+		resp->common->mass_id     = ma_dev->mass_id;
+		/* pkt_status set above */
+		resp->mgmt->token         = req->mgmt->token;
+
+		mausb_pkt_fill_ms_pkt(resp, GFP_ATOMIC);
+		mamgmt_dbg("%s: sending %s packet\n", __func__,
+			mausb_type_to_string(resp->common->pkt_type));
+
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+		transfer->transfer_packet(&resp->pkt, transfer->context);
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	} else {
+		/* we don't know how to handle this packet */
+		mamgmt_dbg("%s: packet type %s not supported\n", __func__,
+			mausb_type_to_string(resp->common->pkt_type));
+		mausb_free_pkt(resp);
+	}
+
+	spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	return ret;
+}
+
+/**
+ * This function parses an incoming management packet, determines
+ * if it is a request or response, and passes the packet to the
+ * proper handler.
+ *
+ * @mgmt_pkt:	A pointer to the incoming MA USB management packet.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt(struct mausb_pkt *mgmt_pkt, struct mausb_mgmt *mgmt)
+{
+	mamgmt_dbg("%s: %s packet received\n", __func__,
+		mausb_type_to_string(mgmt_pkt->common->pkt_type));
+
+	if (mausb_pkt_resp(mgmt_pkt))
+		return mausb_rx_mgmt_resp(mgmt_pkt, mgmt);
+	else
+		return mausb_rx_mgmt_req(mgmt_pkt, mgmt);
+}
+EXPORT_SYMBOL(mausb_rx_mgmt);
+
+/**
+ * Handles sent callback for management packets.
+ *
+ * Request packets are held until a response is received and should not be
+ * freed until then. Response packets can be freed as soon as they are sent out.
+ */
+void mausb_mgmt_pkt_sent(struct ms_pkt *ms_pkt)
+{
+	struct mausb_pkt *pkt;
+
+	pkt = ms_pkt_to_mausb_pkt(ms_pkt);
+
+	if (mausb_pkt_resp(pkt))
+		mausb_free_pkt(pkt);
+}
+EXPORT_SYMBOL(mausb_mgmt_pkt_sent);
+
diff --git a/drivers/staging/mausb/drivers/mausb_mgmt.h b/drivers/staging/mausb/drivers/mausb_mgmt.h
new file mode 100644
index 0000000..d09b019
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mgmt.h
@@ -0,0 +1,90 @@
+/* name:	mausb_mgmt.h
+ * description: Handles management packet structures and declarations common
+ *              to both hosts and devices.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MGMT_H
+#define __MAUSB_MGMT_H
+
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define mamgmt_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mamgmt_dbg(format, arg...)
+#endif
+
+#define mamgmt_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mamgmt_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+struct ma_dev *mausb_mgmt_to_ma_dev(struct mausb_mgmt *mgmt);
+int mausb_tx_dev_mgmt_req(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host);
+int mausb_tx_dev_mgmt_req_ep(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host, struct mausb_host_ep *ma_ep);
+int mausb_rx_mgmt(struct mausb_pkt *mgmt_pkt, struct mausb_mgmt *mgmt);
+void mausb_mgmt_pkt_sent(struct ms_pkt *pkt);
+int mausb_add_mgmt_channel(struct mausb_mgmt *mgmt, struct mausb_ms_drv *drv,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context),
+		void (*pkt_sent)(struct ms_pkt *pkt));
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 08/10] added media agnostic (MA) USB data packet handling
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (6 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

The MA USB Specification outlines packet types and a protocol for
bulk and interrupt transfers. This is where we implement that protocol.
MA USB transfers are initiated by the host via a TransferRequest packet.
The host then either sends data to the device via subsequent
TransferRequest packets (OUT transfer) or receives data from the device
via TransferResponse packets (IN transfer). Each data transfer is
identified by a Request ID number that increments up for each new transfer.
One URB maps to one MA USB transfer. A transfer can consist of one or
more MA USB packets depending on total transfer size. Each MA USB packet
is assigned a Sequence Number with sequence numbers incrementing up for
each new packet. The host sends a TransferAck packet to acknowledge the
end of a transfer or when requested to do so by the device.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_tx-device.c |  847 ++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tx-host.c   | 1211 +++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tx.c        |  318 ++++++
 drivers/staging/mausb/drivers/mausb_tx.h        |  129 +++
 4 files changed, 2505 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.h

diff --git a/drivers/staging/mausb/drivers/mausb_tx-device.c b/drivers/staging/mausb/drivers/mausb_tx-device.c
new file mode 100644
index 0000000..a14df54
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx-device.c
@@ -0,0 +1,847 @@
+/* Name:        mausb_tx_device.c
+ * Description: implements MA USB transfers on device side
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include "mausb_hcd.h"
+#include "mausb_udc.h"
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+
+#include <linux/kthread.h>
+
+int device_transfer_timeout(void *data)
+{
+	struct mausb_host_ep		*ep = (struct mausb_host_ep *) data;
+	struct mausb_udc		*udc = mausb_host_ep_to_maudc(ep);
+
+	while (!kthread_should_stop()) {
+		/*
+		 * make sure actual transfer timeout (i.e. not thread
+		 * setup)
+		 */
+		if (ep->tx_timed_out) {
+			if (ep->state.retry_counter > 0) {
+				maudc_dbg(udc, "%s: device timed out,"
+				      "  resending packet %i\n",
+				       __func__, ep->state.seq_number);
+
+				device_OUT_send_txResp(
+					&ep->active_transfer->state,
+					&ep->state,
+					ep->state.active_request_id,
+					ep->state.seq_number,
+					SUCCESS,
+					false, false, false);
+
+				ep->state.retry_counter--;
+			} else {
+				/*
+				 * TODO: start ping protocol per 5.2.2, if
+				 * successful reset timer and retries. For now
+				 * we just treat as if failed.
+				 */
+				ep->active_transfer->state.transfer_error =
+					true;
+				return -ETIMEDOUT;
+			}
+
+			ep->tx_timed_out = false;
+		}
+
+		/* put thread to sleep to wait for next timeout event */
+		wait_event_interruptible(ep->host_ep_wq,
+			kthread_should_stop() || ep->tx_timed_out);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------IN transfer ------------------------*/
+
+/**
+ * Device-side IN transfer initialization process.
+ *
+ * @ tx_state:	Transfer state to be initialized.
+ * @ ep_state:	Endpoint state to be initialized.
+ * @ tx_req:	TransferReq packet from host that intiated transfer.
+ *
+ * Called every time a transferReq packet is received. Initializes transfer
+ * management variables.
+ */
+void device_init_IN_transfer(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	struct mausb_host_ep *ep = mausb_state_to_ep(ep_state);
+
+	tx_state->transfer_error = false;
+	tx_state->transfer_complete = false;
+	tx_state->rem_size = le32_to_cpu(tx_req->data->remaining_size_credit);
+
+	ep_state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+	ep_state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	ep_state->earliest_unacked = le32_to_cpu(tx_req->data->seq_num);
+	ep_state->active_request_id = tx_req->data->req_id;
+	ep_state->request_id++;
+
+	ep->actual_length = 0;
+
+	/* free old buffer if not previously freed */
+	if (ep->buffer)
+		kfree(ep->buffer);
+
+	/* alocate new buffer for this transfer */
+	ep->buffer = kzalloc(tx_state->rem_size, GFP_ATOMIC);
+}
+
+/* Determines if packet request id or sequence number is outside of the
+ * acceptable range
+ *
+ * Returns true if the packet sequence number or request id is invalid,
+ * otherwise returns false.
+ */
+bool is_invalid_IN_request(struct mausb_ep_state *ep_state,
+		struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	bool			invalid = false;
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(
+					mausb_state_to_ep(ep_state));
+
+	if ((ep_state->earliest_request_id - MAUSB_HALF_REQ_ID) <= r) {
+		if (r < ep_state->earliest_request_id) {
+			maudc_err(udc, "%s: too many outstanding requests\n",
+				__func__);
+			invalid = true;
+		}
+	}
+
+	if ((ep_state->earliest_unacked - MAUSB_HALF_SEQ_NUM) <= SN) {
+		if (SN < ep_state->earliest_unacked) {
+			maudc_err(udc, "%s: too many unacknowledged packets\n",
+				__func__);
+			invalid = true;
+		}
+	}
+
+	if (ep_state->seq_number < SN) {
+		if (SN < (ep_state->seq_number + MAUSB_HALF_SEQ_NUM)) {
+			maudc_err(udc, "%s: too many outstanding sequence"
+			       " numbers\n", __func__);
+			invalid = true;
+		}
+
+	}
+
+	return invalid;
+}
+
+/*
+ * transferReq reception process outlined in MA USB spec.
+ */
+int device_IN_rcvd_txReq(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN  = le32_to_cpu(tx_req->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	if (is_invalid_IN_request(ep_state, tx_req)) {
+		mausb_drop_packet(ep, tx_req);
+		device_IN_send_null_txResp(ep, ep_state->request_id,
+					   INVALID_REQUEST);
+	}
+
+	ep_state->earliest_unacked = SN;
+
+	if (tx_state->eot_detected && !tx_state->transfer_error) {
+		if (tx_state->last_transfer_sn < SN)
+			tx_state->transfer_complete = true;
+		else
+		ep_state->earliest_request_id = r;
+	}
+
+	if (r == ep_state->active_request_id && ep_state->delayed) {
+		maudc_dbg(udc, "%s: transfer %i is delayed, sending txResp with"
+		      " status = TRANSFER_PENDING\n", __func__, r);
+		device_IN_send_null_txResp(ep, r, TRANSFER_PENDING);
+	}
+
+	if (r == ep_state->request_id)
+		device_init_IN_transfer(tx_state, ep_state, tx_req);
+
+	return 0;
+}
+
+/* transferAck packet reception process for device side.
+ *
+ * @tx_state:	Transfer state variables for associated transfer.
+ * @ep_state:	Endpoint state variables for associated transfer.
+ * @tx_ack:	TransferAck packet being received.
+ *
+ * Called when device side driver receives a transferAck packet. Caller should
+ * verify that the request_id in the transferAck packet is valid before
+ * calling this function.
+ */
+int device_IN_ack_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_ack)
+{
+	int			ret = 0;
+	u8			r = tx_ack->data->req_id;
+	u8			u = ep_state->active_request_id;
+	u32			SN = le32_to_cpu(tx_ack->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+	bool			tx_complete = (!tx_state->transfer_error)
+					&& (tx_state->last_transfer_sn < SN);
+	bool			tx_complete_with_error =
+					(tx_state->transfer_error) && (u == r);
+	unsigned long		irq_flags = 0;
+
+	if (is_invalid_IN_request(ep_state, tx_ack))
+		tx_ack->data->common.pkt_status = DROPPED_PACKET;
+
+	switch (tx_ack->data->common.pkt_status) {
+	case DROPPED_PACKET:
+		maudc_dbg(udc, "%s: status = DROPPED_PACKET\n", __func__);
+		mausb_drop_packet(ep, tx_ack);
+		break;
+	case TRANSFER_PENDING:
+		maudc_dbg(udc, "%s: status = TRANSFER_PENDING\n", __func__);
+		if (r != ep_state->active_request_id)
+			mausb_drop_packet(ep, tx_ack);
+		/* else can start power saving measures */
+		break;
+	case MISSING_SEQUENCE_NUMBER:
+		maudc_dbg(udc, "%s: status = MISSING_SEQUENCE_NUMBER\n",
+			__func__);
+		mausb_resend_multi_packets(ep, &ep->resp_list,
+			le32_to_cpu(tx_ack->data->seq_num), irq_flags);
+		break;
+	case SUCCESS:
+		maudc_dbg(udc, "%s: status = SUCCESS\n", __func__);
+		ep_state->earliest_unacked = SN + 1;
+
+		if (tx_state->eot_detected) {
+			if (tx_complete || tx_complete_with_error)
+				tx_state->transfer_complete = true;
+			else
+				ep_state->earliest_request_id = u;
+
+			mausb_cleanup_ma_packets(ep,
+				le32_to_cpu(tx_ack->data->seq_num),
+				tx_ack->data->req_id);
+			kfree(ep->buffer);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Submit a transferResp packet to host with no payload (used for errors).
+ *
+ * Per spec, sequence number field in a null transferResp packet is always
+ * reserved and set to 0
+ */
+int device_IN_send_null_txResp(struct mausb_host_ep *ep, u8 req_id, int status)
+{
+	struct mausb_pkt		*tx_resp;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+
+	tx_resp = mausb_create_dp(NULL, ep->active_transfer, MAUSB_IN,
+		MAUSB_DEV, GFP_ATOMIC);
+
+	if (!tx_resp)
+		return -ENOMEM;
+
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mausb_fill_pkt_ep(tx_resp, ep);
+
+	tx_resp->data->common.pkt_type = TransferResp;
+	tx_resp->data->req_id = req_id;
+	tx_resp->data->seq_num = 0;
+	tx_resp->buffer_length = 0;
+	tx_resp->data->remaining_size_credit = cpu_to_le32(tx_state->rem_size);
+	tx_resp->data->common.pkt_status = status;
+	tx_resp->common->length = cpu_to_le32(mausb_pkt_length(tx_resp));
+
+	mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+	return 0;
+}
+
+/**
+ * Submit a transferResp packet with payload to host (normal data transfer).
+ */
+int device_IN_send_txResp_with_payload(struct mausb_host_ep *ep)
+{
+	int				payload = 0;
+	int				max_buffer_length = 0;
+	int				ep_rem_size = ep->actual_length;
+	struct mausb_ep_state		*ep_state = &ep->state;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_udc		*udc = mausb_host_ep_to_maudc(ep);
+
+	while (ep_rem_size > 0 || ep_state->seq_number == 0)  {
+
+		tx_resp = mausb_create_dp(NULL, ep->active_transfer, MAUSB_IN,
+					  MAUSB_DEV, GFP_ATOMIC);
+
+		if (!tx_resp)
+			return -ENOMEM;
+
+		list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+		mausb_fill_pkt_ep(tx_resp, ep);
+
+		tx_resp->data->common.pkt_type = TransferResp;
+		tx_resp->data->req_id = ep_state->active_request_id;
+		tx_resp->data->seq_num = cpu_to_le32(ep_state->seq_number);
+		tx_resp->data->remaining_size_credit =
+			cpu_to_le32(tx_state->rem_size);
+
+		max_buffer_length =
+			MAUSB_MAX_PACKET_SIZE - sizeof(tx_resp->data);
+
+		if (max_buffer_length <= 0) {
+			maudc_err(udc, "%s: packet buffer error: length"
+			       " = %i\n", __func__, max_buffer_length);
+		} else if (tx_state->rem_size <= 0) {
+			maudc_err(udc, "%s: packet buffer error: rem_size"
+			       " = %i\n", __func__, tx_state->rem_size);
+			ep->buffer = NULL;
+		} else {
+			payload = min_t(int, max_buffer_length,
+					ep_rem_size);
+		}
+
+		tx_resp->buffer = ep->buffer;
+		tx_resp->buffer_length = payload;
+		tx_resp->common->length = cpu_to_le16(mausb_pkt_length(tx_resp));
+
+		/* note: setting ARQ flag for error is optional */
+		if (tx_state->transfer_error) {
+			maudc_err(udc, "%s: transfer error with %i bytes "
+			       "remaining\n", __func__, tx_state->rem_size);
+
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+			tx_resp->data->common.pkt_status = UNSUCCESSFUL;
+
+			/*
+			 * TODO: take corrective action - e.g. clear all
+			 * transfers and restart endpoint
+			 */
+		}
+
+		tx_state->rem_size -= payload;
+		ep_rem_size -= payload;
+		/* note: setting ARQ flag for completion is optional */
+		if (tx_state->rem_size == 0 || ep_rem_size == 0) {
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+			tx_resp->data->common.pkt_status = SUCCESS;
+
+			ep_state->active_request_id++;
+		}
+
+		maudc_dbg(udc, "%s: sending transferResp packet with sequence"
+			" number %i for tranfer %i with %i bytes\n", __func__,
+			le32_to_cpu(tx_resp->data->seq_num),
+			le32_to_cpu(tx_resp->data->req_id), payload);
+
+		mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+		ep_state->seq_number++;
+
+	}
+
+	return 0;
+}
+
+/*------------------ protocol-managed OUT transfer --------------------*/
+
+bool should_drop_OUT_txReq(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state, struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	int			payload_size = tx_req->buffer_length;
+	int			status = SUCCESS;
+	bool			drop = false;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	if (SN > ep_state->seq_number) {
+		maudc_err(udc, "%s: sequence number %i is too large "
+			"(expected < %i)\n", __func__, SN,
+			ep_state->seq_number);
+		drop = true;
+		status = MISSING_SEQUENCE_NUMBER;
+	} else if (SN < ep_state->seq_number) {
+		/* per spec, don't have to send response for this case */
+		maudc_err(udc, "%s: sequence number %i is too small "
+			"(expected >= %i)\n", __func__, SN,
+			ep_state->seq_number);
+		drop = true;
+	} else if (r < ep_state->earliest_request_id) {
+		maudc_err(udc, "%s: request ID %i is too small "
+			"(expected > %i)\n", __func__, r,
+			ep_state->earliest_request_id);
+		drop = true;
+		status = INVALID_REQUEST;
+	} else if (r > ep_state->request_id) {
+		/* account for wraparound */
+		if (ep_state->request_id != 0 && r != MAUSB_MAX_REQ_ID) {
+			maudc_err(udc, "%s: request ID %i is too large "
+				"(expected < %i)\n", __func__, r,
+				ep_state->request_id);
+			drop = true;
+			status = INVALID_REQUEST;
+		}
+	} else if ((payload_size + ep_state->occupancy)
+			> ep_state->rx_buf_size) {
+		maudc_err(udc, "%s: payload (%i bytes) is too large for buffer"
+			" (%i bytes)\n", __func__, payload_size,
+			ep_state->occupancy);
+		drop = true;
+		status = TRANSFER_DATA_BUFFER_ERROR;
+	}
+
+	/*
+	 * send txResp to host with appropriate status if txReq is going to
+	 * get dropped
+	 */
+	if (status) {
+		device_OUT_send_txResp(tx_state, ep_state,
+			ep_state->request_id, ep_state->seq_number, status,
+			false, false, false);
+	}
+
+	return drop;
+}
+
+/**
+ * Handles receipt of a transferRequest packet.
+ *
+ * @tx_state: State variables for associated transfer.
+ * @ep_state: State variables for associated device endpoint.
+ * @tx_req:   TransferRequest packet being received.
+ */
+int device_OUT_txReq_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	u8			req_id = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	int			ret = 0;
+	int			payload_size = tx_req->buffer_length;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	maudc_dbg(udc, "%s: received transferReq packet %i for transfer %i\n",
+		__func__, SN, req_id);
+
+	if (should_drop_OUT_txReq(ep_state, tx_state, tx_req)) {
+		maudc_err(udc, "%s: dropping packet %i\n", __func__, SN);
+		mausb_drop_packet(ep, tx_req);
+		return 0;
+	}
+
+	/* start new transfer */
+	if (req_id == (ep_state->request_id)) {
+		tx_state->transfer_error = false;
+		tx_state->transfer_complete = false;
+		tx_state->eot_detected = false;
+		tx_state->rem_size =
+			le32_to_cpu(tx_req->data->remaining_size_credit);
+		tx_state->payload_size = 0;
+		ep->active_transfer->transfer_size = tx_state->rem_size;
+		ep_state->active_request_id = req_id;
+		INIT_LIST_HEAD(&ep->req_list);
+		INIT_LIST_HEAD(&ep->resp_list);
+
+		ep->actual_length = 0;
+
+		ep_state->request_id =
+			mausb_req_id_add(ep_state->request_id, 1);
+	}
+
+	ep->buffer = tx_req->buffer;
+	ep_state->occupancy += payload_size;
+	ret = device_OUT_deliver_payload(tx_req, ep_state, tx_state);
+	ep_state->occupancy -= payload_size;
+
+	ep_state->seq_number++;
+
+	return 0;
+}
+
+/**
+ * Transmits a transferReq or transferAck packet.
+ */
+int device_OUT_send_txResp(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, u32 req_id, u32 seq_num,
+		int status, bool retry, bool eot, bool arq)
+{
+	struct mausb_host_ep *ep = mausb_state_to_ep(ep_state);
+	struct mausb_pkt *tx_resp = mausb_create_dp(NULL, ep->active_transfer,
+				     MAUSB_OUT, MAUSB_DEV, GFP_ATOMIC);
+	struct mausb_udc *udc = mausb_host_ep_to_maudc(ep);
+
+	if (!tx_resp)
+		return -ENOMEM;
+
+	mausb_fill_pkt_ep(tx_resp, ep);
+
+	tx_resp->data->common.pkt_type = TransferResp;
+	tx_resp->data->req_id = req_id;
+	tx_resp->data->seq_num = cpu_to_le32(seq_num);
+	tx_resp->data->common.pkt_status = status;
+	tx_resp->data->remaining_size_credit =
+		cpu_to_le32(ep_state->rx_buf_size - ep_state->occupancy);
+
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+
+	tx_resp->common->length = cpu_to_le16(mausb_pkt_length(tx_resp));
+
+	if (retry)
+		tx_resp->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+
+	if (eot)
+		tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+
+	if (arq)
+		tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+
+	maudc_dbg(udc, "%s: sending transferResp packet %i for transfer %i\n",
+		__func__, le32_to_cpu(tx_resp->data->seq_num),
+		tx_resp->data->req_id);
+
+	/* send transferResp packet to host */
+	mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+	return 0;
+}
+
+/**
+ * Handles receipt of a transferAck packet.
+ *
+ * Caller should ensure that transfer complete and error flags are not set.
+ * Note that what to do isn't defined in spec - we are on our own for this one!
+ */
+void device_OUT_ack_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state,
+		struct mausb_pkt *tx_ack)
+{
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	maudc_dbg(udc, "%s: received transferAck packet for transfer %i\n",
+		__func__, tx_ack->data->req_id);
+
+	ep_state->occupancy = 0;
+	mausb_cleanup_ma_packets(ep, le32_to_cpu(tx_ack->data->seq_num),
+		tx_ack->data->req_id);
+}
+
+/*
+ * Copy payload from transferRequest into device buffer.
+ *
+ * @tx_req:   TransferRequest with payload to be delivered.
+ * @ep_state: State variables for associated device endpoint.
+ * @tx_state: State variables for associated transfer.
+ *
+ * Caller should ensure that transfer complete and error flags are not set.
+ * This function also includes payload delivery process outlined in spec.
+ */
+int device_OUT_deliver_payload(struct mausb_pkt *tx_req,
+		struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state)
+{
+	u32			req_sn = le32_to_cpu(tx_req->data->seq_num);
+	int			payload_size;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	/* payload delivery process */
+	payload_size = do_ma_transfer(ep, tx_req, MAUSB_OUT);
+
+	/* payload delivery confirmation process */
+	if (payload_size < 0) {
+		maudc_err(udc, "%s: transfer error %i\n", __func__,
+			payload_size);
+
+		device_OUT_send_txResp(tx_state, ep_state, tx_req->data->req_id,
+			le32_to_cpu(tx_req->data->seq_num), UNSUCCESSFUL,
+				       false, true, false);
+	}
+
+	else {
+		ep_state->earliest_unacked = req_sn + 1;
+		tx_state->payload_size = payload_size - tx_state->payload_size;
+		tx_state->rem_size =
+			le32_to_cpu(tx_req->data->remaining_size_credit);
+		tx_state->payload_size = payload_size;
+
+		maudc_dbg(udc, "%s: delivered %i bytes with %i remaining\n",
+		       __func__, payload_size, tx_state->rem_size);
+
+		/* control response packet */
+		if (tx_req->setup) {
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, true, true);
+
+		/* end of transfer response packet */
+		} else if (tx_state->rem_size == 0) {
+			tx_state->last_transfer_sn = req_sn;
+
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, true, true);
+		} else if (tx_req->data->eps_tflags & MAUSB_PKT_TFLAG_ARQ) {
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, false, true);
+		}
+	}
+
+	return 0;
+}
+
+/*------------------ transfer interfaces ----------------------------*/
+
+/**
+ * Called to receive both transferRequest and transferAck packets.
+ * For transferRequests, a new transfer is initiated - transfer state values
+ * are initialized and a request is send to the device to get data. For
+ * transferAcks, a transfer is ended (either successfully or with error,
+ * depending on transferAck packet status).
+ */
+int receive_ma_packet_IN(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	list_add_tail(&pkt->pkt_list, &ep->req_list);
+
+	udc = mausb_host_ep_to_maudc(ep);
+
+	if (mausb_is_a_retry(ep, &ep->resp_list, pkt))
+		return 0;
+
+	switch (pkt->data->common.pkt_type) {
+	case TransferReq:
+		maudc_dbg(udc, "%s: received transferReq %i for transfer %i\n",
+			__func__, le32_to_cpu(pkt->data->seq_num),
+			pkt->data->req_id);
+		device_IN_rcvd_txReq(&ep->state, &ep->active_transfer->state,
+			pkt);
+		ret = do_ma_transfer(ep, pkt, MAUSB_IN);
+		ret = device_IN_send_txResp_with_payload(ep);
+		break;
+	case TransferAck:
+		maudc_dbg(udc, "%s: received transferAck for transfer %i\n",
+			__func__, pkt->data->req_id);
+		ret = device_IN_ack_rcvd(&ep->active_transfer->state,
+			&ep->state, pkt);
+		break;
+	default:
+		maudc_err(udc, "%s: invalid packet type/subtype %i\n",
+			__func__, pkt->data->common.pkt_type);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * Receives both transferReq and transferAck packets for OUT transfers. When a
+ * packet is received, it is put on a list for handling. If the endpoint is not
+ * already handling a packet, it starts iterating through the list of received
+ * packets.
+ */
+int receive_ma_packet_OUT(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	list_add_tail(&pkt->pkt_list, &ep->req_list);
+
+	udc = mausb_host_ep_to_maudc(ep);
+
+	if (mausb_is_a_retry(ep, &ep->resp_list, pkt))
+		return 0;
+
+	/* determine if packet is a transferRequest */
+	if (pkt->data->common.pkt_type == TransferReq) {
+		maudc_dbg(udc, "%s: received transferReq %i for transfer %i\n",
+			__func__, le32_to_cpu(pkt->data->seq_num),
+			pkt->data->req_id);
+		ret = device_OUT_txReq_rcvd(&ep->active_transfer->state,
+			&ep->state, pkt);
+
+	/* if not a transferReq, it should be a transferAck */
+	} else if (pkt->data->common.pkt_type == TransferAck) {
+		maudc_dbg(udc, "%s: received transferAck for transfer %i\n",
+			__func__, pkt->data->req_id);
+		device_OUT_ack_rcvd(&ep->active_transfer->state, &ep->state,
+			pkt);
+	} else {
+		/* TODO: deal with invalid packet type */
+	}
+
+	return ret;
+}
+
+/**
+ * Called when a transferReq is received on a control endpoint.
+ *
+ * @ms_pkt:	Packet being received.
+ * @context:	Device endpoint associated with transfer (this should always
+ *		be ep0).
+ */
+int receive_ma_packet_control(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	udc = mausb_host_ep_to_maudc(ep);
+
+	/*
+	 * A new control transfer begins with a transfer request carrying setup
+	 * data and sequence number 0.
+	 */
+	if (pkt->setup) {
+		ep->state.seq_number = 0;
+		ep->actual_length = 0;
+		ep->active_transfer->state.rem_size =
+			le32_to_cpu(pkt->data->remaining_size_credit);
+
+		/*
+		 * Determine if this is a control IN or OUT - if there is data
+		 * in the packet, or the host is requesting no data, we are
+		 * an OUT.
+		 */
+		if (0 != pkt->buffer_length ||
+		    0 == le32_to_cpu(pkt->data->remaining_size_credit)) {
+
+			ep->control_dir = MAUSB_OUT;
+
+		} else
+			ep->control_dir = MAUSB_IN;
+	}
+
+	kfree(pkt);
+	pkt = NULL;
+
+	if (MAUSB_IN == ep->control_dir)
+		ret = receive_ma_packet_IN(ms_pkt, context);
+	else
+		ret = receive_ma_packet_OUT(ms_pkt, context);
+
+	return ret;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_tx-host.c b/drivers/staging/mausb/drivers/mausb_tx-host.c
new file mode 100644
index 0000000..7f495e9
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx-host.c
@@ -0,0 +1,1211 @@
+/* Name:        mausb_tx-host.c
+ * Description: implement host-side Ma USB transfers
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#include <linux/kthread.h>
+
+#include "mausb_hcd.h"
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+
+/**
+ * Handles a data transfer timeout event, then sleeps until the next
+ * timeout event. Timeout events that wish to use this thread should
+ * set the ep->tx_timed_out flag to true to ensure that the thread
+ * is woken.
+ */
+int host_transfer_timeout(void *data)
+{
+	int				err = 0;
+	int				dir_in = 0;
+	int				seq_num = 0;
+	struct mausb_host_ep		*ep = (struct mausb_host_ep *) data;
+	struct mausb_ep_state		*ep_state = &ep->state;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_pkt		*tx_req;
+	unsigned long			irq_flags;
+	struct mausb_hcd		*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	while (!kthread_should_stop()) {
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		/*
+		 * make sure there is an active transfer for timeout
+		 * to handle (i.e. not thread creation/initialization)
+		 */
+		if (ep->active_transfer && ep->active_transfer->urb) {
+			tx_state = &ep->active_transfer->state;
+			dir_in = usb_pipein(ep->active_transfer->urb->pipe);
+
+			seq_num = ep_state->earliest_unacked;
+
+			if (ep_state->retry_counter >  0) {
+				mausb_dbg(mhcd, "%s: host timed out waiting"
+					" for pkt %i\n", __func__, seq_num);
+
+				/* see if we have corresponding request */
+				err = mausb_resend_multi_packets(ep,
+					&ep->req_list, seq_num, irq_flags);
+
+				/* if not, send new req */
+				if (err != 0) {
+					spin_unlock_irqrestore(&ep->ep_lock,
+								irq_flags);
+
+					tx_req = mausb_create_dp(NULL,
+						 ep->active_transfer,
+						 MAUSB_IN, MAUSB_HOST,
+						 GFP_ATOMIC);
+
+					tx_req->data->common.pkt_type =
+						TransferReq;
+					tx_req->data->seq_num = seq_num;
+					tx_req->data->common.pkt_status =
+						SUCCESS;
+					tx_req->data->req_id =
+						ep_state->active_request_id;
+					tx_req->common->ver_flags
+						|= MAUSB_PKT_FLAG_RETRY;
+					tx_req->common->length =
+						mausb_pkt_length(tx_req);
+
+					/* submit packet for transport */
+					mausb_transfer_data_pkt(tx_req, ep,
+								GFP_ATOMIC);
+
+					spin_lock_irqsave(&ep->ep_lock,
+								irq_flags);
+
+					list_add_tail(&tx_req->pkt_list,
+						      &ep->req_list);
+				}
+
+				ep_state->retry_counter--;
+			} else {
+				/*
+				 * Can optionally initiate ping process in sec
+				 * 5.2.3 of spec. For now we just treat as if
+				 * ping protocol failed. */
+				tx_state->transfer_error = true;
+
+				spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+				mausb_unlink_giveback_urb(ep->active_transfer,
+							  -ETIMEDOUT);
+				spin_lock_irqsave(&ep->ep_lock, irq_flags);
+			}
+		}
+
+		ep->tx_timed_out = false;
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		/* put thread to sleep to wait for next timeout event */
+		wait_event_interruptible(ep->host_ep_wq,
+			kthread_should_stop() || ep->tx_timed_out);
+	}
+
+	return 0;
+}
+
+/* Initialize transfer state, for beginning a new transfer */
+static void mausb_host_init_tx_state(struct mausb_transfer_state *tx_state,
+		u32 tx_size)
+{
+	tx_state->transfer_error = false;
+	tx_state->transfer_complete = false;
+	tx_state->eot_detected = false;
+	tx_state->transfer_acked = false;
+	tx_state->rem_size = tx_size;
+	tx_state->payload_size = 0;
+}
+
+/*--------------------- IN transfers ------------------------------*/
+
+/**
+ * Host-side IN transfer initialization process.
+ *
+ * @tx_state: Transfer state to be initialized.
+ * @ep_state: Endpoint state to be initialized.
+ * @maurb:    maurb associated with transfer.
+ *
+ * Called whenever a new IN transfer is initiated by the host.
+ * Initializes transfer state variables, resets timers, then submits a
+ * transferReq packet to the device side driver. After successful submission
+ * of a transferReq packet, the transfer request id is incremented by one
+ * for the next transfer. When transfer request id reaches its max value,
+ * it wraps back around to zero (per mausb spec requirements).
+ */
+void host_init_IN_transfer(struct mausb_transfer_state *tx_state,
+		struct mausb_host_ep *ep, struct mausb_urb *maurb)
+{
+	int			status = SUCCESS;
+	u32			tx_size = maurb->urb->transfer_buffer_length;
+	unsigned long		irq_flags;
+	struct mausb_ep_state	*ep_state = &ep->state;
+	struct mausb_pkt	*tx_req = mausb_create_dp(&status, maurb,
+					MAUSB_IN, MAUSB_HOST, GFP_ATOMIC);
+
+	if (!tx_req)
+		return;
+
+	mausb_fill_pkt_ep(tx_req, ep);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* fill the transfer request */
+	tx_req->data->common.pkt_type = TransferReq;
+	tx_req->data->remaining_size_credit =
+		maurb->urb->transfer_buffer_length;
+	tx_req->data->req_id = ep_state->request_id;
+	tx_req->data->seq_num = cpu_to_le32(ep_state->seq_number);
+
+	if (mausb_pkt_has_setup_data(tx_req->data)) {
+		tx_req->setup =
+			(struct usb_ctrlrequest *) maurb->urb->setup_packet;
+	}
+
+	tx_req->common->length = mausb_pkt_length(tx_req);
+
+	/* set the transfer state */
+	mausb_host_init_tx_state(tx_state, tx_size);
+
+	/* set the endpoint state */
+	ep->tx_timed_out = false;
+	ep_state->active_request_id = ep_state->request_id;
+	ep_state->keep_alive_timer = MAUSB_TRANSFER_TIMEOUT;
+	ep_state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	ep_state->request_id = mausb_req_id_add(ep_state->request_id, 1);
+
+	/* send the packet */
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	host_IN_txReq_transmit(tx_req, ep, tx_state);
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* start timeout timer */
+	mod_timer(&ep->timer,
+	jiffies + msecs_to_jiffies(ep_state->keep_alive_timer));
+
+	/* add the packet to the endpoint */
+	list_add_tail(&tx_req->pkt_list, &ep->req_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+}
+
+/**
+* Releases an MA USB packet to the data channel and updates state.
+*/
+void host_IN_txReq_transmit(struct mausb_pkt *tx_req, struct mausb_host_ep *ep,
+		struct mausb_transfer_state *tx_state)
+{
+	int			ret;
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	mausb_dbg(mhcd, "%s: sending pkt %i for request %i\n", __func__,
+		  le32_to_cpu(tx_req->data->seq_num), tx_req->data->req_id);
+
+	/* submit packet for transport */
+	ret = mausb_transfer_data_pkt(tx_req, ep, GFP_ATOMIC);
+
+	if (tx_state->eot_detected && !tx_state->transfer_error)
+		if (tx_state->last_transfer_sn
+			< le32_to_cpu(tx_req->data->seq_num)) {
+			tx_state->transfer_acked = true;
+		/* TODO:transfer_completion_timer = aMaxTransferLifetime */
+		}
+}
+
+/**
+ * Transmits a TransferAck packet.
+ *
+ * @tx_state: State information associated with this transfer.
+ * @in:	      Set to true for an IN transfer.
+ * @ep_state: State information associated with transfer endpoint.
+ * @status:   Status to fill transferAck packet status field.
+ *	      Note: unless otherwise specified in spec, should be SUCCESS.
+ * @seq_num:  Sequence number to fill transferAck packet sequence number field.
+ *	      Note: should be the greatest sequence number of the packets to
+ *	      be acked.
+ *
+ * Called to acknowledge end of transfer or when a packet that otherwise
+ * requires acknowledgement (i.e. ARQ flag is set) is received.
+ */
+int host_send_ack(struct mausb_transfer_state *tx_state, bool in,
+		struct mausb_ep_state *ep_state, int status, u32 seq_num)
+{
+	struct mausb_urb	*maurb = container_of(tx_state,
+					struct mausb_urb, state);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_pkt	*tx_ack = mausb_create_dp(NULL, maurb, in,
+					MAUSB_HOST, GFP_ATOMIC);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	if (tx_ack == NULL)
+		return -ENOMEM;
+
+	mausb_fill_pkt_ep(tx_ack, ep);
+
+	tx_ack->data->common.pkt_type = TransferAck;
+	tx_ack->data->seq_num = cpu_to_le32(seq_num);
+	tx_ack->data->common.pkt_status = status;
+	tx_ack->data->req_id = ep_state->active_request_id;
+	tx_ack->common->length = cpu_to_le16(mausb_pkt_length(tx_ack));
+
+	mausb_dbg(mhcd, "%s: sending ack for transfer %i\n",
+	       __func__, ep_state->active_request_id);
+
+	if (in && tx_state->eot_detected) {
+		if (mausb_transfer_is_complete(tx_state, seq_num)) {
+			tx_state->transfer_acked = true;
+			/* TODO: set completion timer */
+		}
+
+		/* since we're done, clear out packet lists and free memory */
+		mausb_cleanup_ma_packets(ep, seq_num,
+			 ep_state->earliest_request_id);
+
+	} else if (!in) {
+		tx_state->transfer_acked = true;
+		/* TODO: set transfer completion timer = aMaxTransferLifetime */
+	}
+
+	/* submit packet for transport */
+	mausb_transfer_data_pkt(tx_ack, ep, GFP_ATOMIC);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	list_add_tail(&tx_ack->pkt_list, &ep->req_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Deliver payload from transferResp to target urb.
+ *
+ * @tx_resp:	transferResponse packet with data to be transfered.
+ * @maurb:	urb associated with transfer.
+ *
+ * Must ensure that transfer has not been completed (transfer_complete is
+ * false) and there are no transfer errors (transfer_error is false) before
+ * calling.
+ *
+ * Returns length in bytes of data delivered.
+ */
+int host_IN_deliver_payload(struct mausb_pkt *tx_resp, struct mausb_urb *maurb)
+{
+	int			offset;
+	int			length = tx_resp->buffer_length;
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(maurb->ep);
+
+	if (length == 0) {
+		mausb_err(mhcd, "%s: no payload (length = 0)\n", __func__);
+		return length;
+	}
+
+	if (!maurb || !maurb->urb || !maurb->urb->transfer_buffer) {
+		mausb_err(mhcd, "%s: urb not found\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!tx_resp || !tx_resp->buffer) {
+		mausb_err(mhcd, "%s: no transferResponse buffer\n", __func__);
+		return -EINVAL;
+	}
+
+	offset = maurb->urb->transfer_buffer_length - maurb->state.rem_size;
+
+	memcpy(maurb->urb->transfer_buffer + offset, tx_resp->buffer, length);
+
+	maurb->urb->actual_length += length;
+
+	return length;
+}
+
+/**
+ * Determines if a received transfer response should be dropped
+ * due to invalid request or sequence number. Note: this fuction does not
+ * actually drop any packets.
+ *
+ * The caller should be holding the endpoints spinlock.
+ *
+ * Returns true if packet should be dropped, otherwise returns false.
+ */
+bool should_drop_txResp(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp, bool in)
+{
+	bool			drop = false;
+	u8			r = tx_resp->data->req_id;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	/* transfer is complete or error flag is set */
+	if (tx_state->transfer_complete || tx_state->transfer_error) {
+		mausb_err(mhcd, "%s: transfer %i already completed %s error\n",
+			__func__, r,
+			(tx_state->transfer_error ? "with" : "without:"));
+		drop = true;
+	}
+
+	/* request id is invalid */
+	if (mausb_req_id_lt(r, ep_state->earliest_request_id) ||
+		(mausb_req_id_gt_eq(r, ep_state->request_id))) {
+
+		mausb_err(mhcd, "%s: request ID %i is invalid\n", __func__, r);
+
+		host_send_ack(tx_state, MAUSB_IN, ep_state,
+			INVALID_REQUEST, SN);
+		drop = true;
+	}
+
+	/*
+	 * Sequence number is reserved for TRANSFER_PENDING,
+	 * so skip sequence number checks.
+	 */
+	if (TRANSFER_PENDING == tx_resp->common->pkt_status)
+		return drop;
+
+	/* sequence number is larger than expected */
+	if (mausb_seq_num_gt(SN, ep_state->seq_number)) {
+
+		mausb_err(mhcd, "%s: missing sequence number - expected %i but"
+			" received %i\n", __func__, ep_state->seq_number, SN);
+
+		drop = true;
+		host_send_ack(tx_state, MAUSB_IN, ep_state,
+			MISSING_SEQUENCE_NUMBER, ep_state->seq_number);
+	}
+
+	/* sequence number is invalid */
+	if ((!in && mausb_seq_num_lt(SN, ep_state->earliest_unacked)) ||
+		(in && mausb_seq_num_lt(SN, ep_state->seq_number))) {
+
+		mausb_err(mhcd, "%s: invalid sequence number %i for %s"
+			" transfer\n", __func__, SN, (in ? "IN" : "OUT"));
+		drop = true;
+	}
+
+	return drop;
+}
+
+/**
+ * Handles receipt of transferResp.
+ *
+ * @ep_state: State information associated with transfer endpoint.
+ * @tx_state: State information associated with transfer.
+ * @tx_resp:  transferResponse packet being received.
+ *
+ * Called when host receives a transferResp packet from a device during an IN
+ * transfer. Updates host-side transfer and endpoint states and checks for
+ * packet errors.
+ *
+ * Returns length of payload copied into host buffer. If nothing was copied
+ * returns 0 or errno if error.
+ */
+int host_IN_txResp_rcvd(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp)
+{
+	int			length = 0;
+	u8			r = tx_resp->data->req_id;
+	u8			eps_flags = tx_resp->data->eps_tflags;
+	u32			payload_size = tx_resp->buffer_length;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	/* look for sequence number and request ID errors */
+	if (should_drop_txResp(ep_state, tx_state, tx_resp, MAUSB_IN)) {
+		mausb_drop_packet(ep, tx_resp);
+		return length;
+	}
+
+	switch (tx_resp->data->common.pkt_status) {
+	case DROPPED_PACKET:
+		mausb_err(mhcd, "%s: status = DROPPED_PACKET\n", __func__);
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	case INVALID_REQUEST: /* same as MISSING_REQUEST_ID in spec */
+		mausb_err(mhcd, "%s: status = INVALID_REQUEST\n", __func__);
+		/*
+		 * TODO: invalidate all outstanding transferReqs with req id
+		 * from r to ep_state->request_id - 1
+		 */
+		ep_state->request_id = r;
+		break;
+	case TRANSFER_PENDING:
+		mausb_err(mhcd, "%s: status = TRANSFER_PENDING\n", __func__);
+		ep_state->keep_alive_timer =
+			(tx_state->k * MAUSB_TRANSFER_KEEP_ALIVE);
+		ep_state->retry_counter = ep_state->transfer_retries;
+		if (eps_flags & MAUSB_PKT_TFLAG_ARQ) {
+			/*
+			 * NOTE: per spec, the sequence number in the ack packet
+			 * is reserved and set to 0.
+			 */
+			host_send_ack(tx_state, MAUSB_IN, ep_state,
+				TRANSFER_PENDING, 0);
+		}
+		break;
+	case TRANSFER_EP_STALL:
+		printk(KERN_DEBUG "%s: status = TRANSFER_EP_STALL\n", __func__);
+		if (eps_flags & MAUSB_PKT_TFLAG_EOT) {
+			host_send_ack(tx_state, MAUSB_IN, ep_state,
+				      TRANSFER_EP_STALL, SN);
+
+			tx_state->eot_detected = true;
+		}
+		break;
+	case SUCCESS:
+		ep_state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+		ep_state->transfer_retries = MAUSB_BULK_TRANSFER_RETRIES;
+
+		if (SN == ep_state->seq_number) {
+			if (tx_state->rem_size >= payload_size) {
+				length = host_IN_deliver_payload(tx_resp,
+					 container_of(tx_state,
+						struct mausb_urb, state));
+
+				ep_state->seq_number++;
+				tx_state->rem_size -= length;
+
+				if (eps_flags & MAUSB_PKT_TFLAG_ARQ ||
+					eps_flags & MAUSB_PKT_TFLAG_EOT) {
+					host_send_ack(tx_state, MAUSB_IN,
+						ep_state, SUCCESS, SN);
+				}
+
+				if (eps_flags & MAUSB_PKT_TFLAG_EOT) {
+					tx_state->eot_detected = true;
+					tx_state->last_transfer_sn = SN;
+					ep_state->earliest_request_id =
+						mausb_req_id_add(
+						ep_state->earliest_request_id,
+						1);
+					ep_state->active_request_id =
+						mausb_req_id_add(
+						ep_state->active_request_id, 1);
+
+					/*
+					 * Can optionally send ack here.
+					 * If don't send ack, next txReq
+					 * serves as ack.
+					 */
+
+					if (tx_state->rem_size > 0) {
+						tx_state->transfer_error = true;
+						mausb_dbg(mhcd, "%s: end of "
+						"transfer with %i bytes left\n",
+						__func__, tx_state->rem_size);
+					}
+				}
+			} else {
+				/*
+				 * For now just drop packet, but can also
+				 * optionally admit up to rem_size of payload
+				 * into buffer.
+				 */
+				tx_state->transfer_error = true;
+				mausb_drop_packet(ep, tx_resp);
+				host_send_ack(tx_state, MAUSB_IN, ep_state,
+						 TRANSFER_SIZE_ERROR, SN);
+			}
+		}
+		break;
+	default:
+		mausb_dbg(mhcd, "%s: status = %i, dropping packet\n",
+		       __func__, tx_resp->data->common.pkt_status);
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	}
+
+	return length;
+}
+
+
+/*------------------ protocol-managed OUT transfers -----------------*/
+
+/**
+ * @ tx_state: Transfer state to be initialized.
+ * @ ep:       Endpoint associated with transfer.
+ * @ tx_size:  Transfer size in bytes.
+ *
+ * Called every time a new OUT transfer is initiated. Initializes transfer
+ * state variables.
+ */
+void host_init_OUT_transfer(struct mausb_transfer_state *tx_state,
+	struct mausb_host_ep *ep, u32 tx_size)
+{
+	unsigned long irq_flags;
+
+	mausb_host_init_tx_state(tx_state, tx_size);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	ep->tx_timed_out = false;
+
+	ep->state.active_request_id = ep->state.request_id;
+
+	/*
+	 * Increment request id for new transfer (or go back to zero
+	 * if max sequence number is reached.
+	 */
+	ep->state.request_id = mausb_req_id_add(ep->state.request_id, 1);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+}
+
+/**
+ * Send a transferReq packet to a device.
+ *
+ * @tx_state:     State variables for transfer.
+ * @ep_state:     State variables for endpoint associated with transfer.
+ * @tx_req;	  MA USB transferReq packet to be sent out.
+ */
+int host_OUT_send_txReq(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	int			i = 0;
+	int			payload_size = tx_req->buffer_length;
+	int			mausb_pkt_head_size;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	mausb_pkt_head_size = mausb_pkt_header_length(tx_req->common);
+
+	if (payload_size > ep_state->rx_buf_size) {
+		mausb_dbg(mhcd, "%s: payload of %i bytes is too big - device "
+		       "can only receive %i bytes\n", __func__, payload_size,
+		       ep_state->rx_buf_size);
+		while (payload_size > ep_state->rx_buf_size &&
+		       i <= MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT) {
+			msleep(1);
+			i++;
+		}
+		if (i > MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT) {
+			mausb_dbg(mhcd,
+				"wait gadget receive buffer free time out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	if (mausb_seq_num_lt(ep_state->seq_number,
+				ep_state->earliest_unacked)) {
+
+		mausb_err(mhcd, "%s: too many outstanding packets\n",
+		       __func__);
+		/* TODO: transmit packet at later time (flow control) */
+	}
+
+	if (payload_size <= ep_state->rx_buf_size) {
+		/*
+		 * Credit remains less than 1 max_packet_payload,
+		 * and there are more than 1 max_packet_payload data to
+		 * transfer. Ask device to update credit.
+		 */
+		if (ep_state->rx_buf_size - payload_size <
+		    MAUSB_MAX_PACKET_SIZE - mausb_pkt_head_size  &&
+		    tx_state->rem_size > ep_state->rx_buf_size - payload_size) {
+			mausb_dbg(mhcd, "request ARQ, payload_size: %d,"
+				" rx_buf_size: %d\n", payload_size,
+				ep_state->rx_buf_size);
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+		}
+		/* look for end of transfer */
+		if (tx_state->rem_size == 0) {
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+		}
+
+		/* set timer if expecting a response */
+		if (tx_req->data->eps_tflags & MAUSB_PKT_TFLAG_ARQ &&
+		    le32_to_cpu(tx_req->data->seq_num) != 0) {
+			tx_state->ack_transfer_sn =
+				le32_to_cpu(tx_req->data->seq_num);
+			mod_timer(&ep->timer, jiffies +
+				msecs_to_jiffies(MAUSB_TRANSFER_TIMEOUT));
+		}
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		tx_req->common->length = cpu_to_le16(mausb_pkt_length(tx_req));
+
+		mausb_dbg(mhcd, "%s: sending transferRequest with sequence"
+			" number %i for request %i with %i bytes of payload\n",
+			__func__, le32_to_cpu(tx_req->data->seq_num),
+			le32_to_cpu(tx_req->data->req_id),
+			tx_req->buffer_length);
+
+		tx_state->payload_size += payload_size;
+
+		/* submit packet for transport */
+		mausb_transfer_data_pkt(tx_req, ep, GFP_ATOMIC);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+		ep_state->rx_buf_size -= payload_size;
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Determines if this urb is a for a control transfer. For host side only
+ * (device doesn't have urbs).
+ */
+static bool mausb_control_xfer(struct mausb_urb *maurb)
+{
+	return (usb_endpoint_type(&maurb->urb->ep->desc) ==
+		USB_ENDPOINT_XFER_CONTROL && maurb->urb->setup_packet);
+}
+
+/**
+ * Create and send OUT transferRequest packets for a given transfer.
+ *
+ * @tx_state:	State associated with transfer.
+ * @ep_state:	State associated with transfer endpoint.
+ * @maurb:	MA USB urb associated with transfer.
+ */
+int host_OUT_generate_txReqs(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_urb *maurb)
+{
+	int				offset = 0;
+	int				pkt_length = 0;
+	int				payload_size = 0;
+	int				max_buffer_length = 0;
+	struct				mausb_pkt *tx_req;
+	struct mausb_host_ep		*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd		*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long irq_flags;
+
+	/*
+	 * Always generate at least one OUT transferReq (OUT control
+	 * transfers may only contain setup data).
+	 */
+	do {
+		/* create transferReq and set packet field values */
+		tx_req = mausb_create_dp(SUCCESS, maurb, MAUSB_OUT,
+					 MAUSB_HOST, GFP_ATOMIC);
+
+		if (!tx_req)
+			return -ENOMEM;
+
+		mausb_fill_pkt_ep(tx_req, ep);
+		tx_req->data->common.pkt_type = TransferReq;
+		tx_req->data->req_id = ep_state->active_request_id;
+		tx_req->data->seq_num = cpu_to_le32(ep_state->seq_number);
+		tx_req->data->remaining_size_credit =
+			cpu_to_le32(tx_state->rem_size);
+		tx_req->buffer_length = 0;
+		tx_req->nents = 0;
+
+		/* add setup data (If necessary) */
+		if (mausb_pkt_has_setup_data(tx_req->data)) {
+			tx_req->setup = (struct usb_ctrlrequest *)
+						maurb->urb->setup_packet;
+		}
+
+		/* calculate max packet buffer size */
+		pkt_length = mausb_pkt_length(tx_req);
+		max_buffer_length = MAUSB_MAX_PACKET_SIZE - pkt_length;
+		payload_size = min_t(int, max_buffer_length,
+				     tx_state->rem_size);
+
+		/* a control transfer can be empty, but nothing else */
+		if (payload_size <= 0 &&
+				!mausb_pkt_has_setup_data(tx_req->data)) {
+			mausb_err(mhcd, "%s: packet error - no room for "
+			       "payload (buffer size is %i)\n", __func__,
+			       payload_size);
+			return -ENOBUFS;
+		} else if (payload_size > 0) {
+
+			if (!maurb->urb->transfer_buffer) {
+				mausb_err(mhcd, "%s: no transfer buffer\n",
+				__func__);
+			}
+
+			/* create packet buffer and fill */
+			tx_req->buffer = maurb->urb->transfer_buffer + offset;
+			if (!tx_req->buffer) {
+				mausb_free_pkt(tx_req);
+				return -ENOMEM;
+			}
+
+			tx_req->buffer_length = payload_size;
+		}
+
+		/* update state variables */
+		offset += payload_size;
+		tx_state->rem_size -= payload_size;
+		tx_req->data->remaining_size_credit = tx_state->rem_size;
+
+		/* send transferReq packet to device */
+		host_OUT_send_txReq(tx_state, ep_state, tx_req);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		ep_state->seq_number =
+				mausb_seq_num_add(ep_state->seq_number, 1);
+		list_add_tail(&tx_req->pkt_list, &ep->req_list);
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	} while (tx_state->rem_size > 0);
+
+	return 0;
+}
+
+/**
+ * Updates transfer and endpoint states after a transferResp is received.
+ *
+ * @ep_state: State information for enpoint associated with transfer.
+ * @tx_state: State information for transfer in progress.
+ * @tx_resp:  transferResponse packet that has been received.
+ *
+ * Called whenever a transferResp packet is received. Returns size in bytes
+ * of payload transferred.
+ */
+int host_OUT_txResp_rcvd(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp)
+{
+	int			payload_size = 0;
+	u8			status = tx_resp->common->pkt_status;
+	u8			ep_flags = tx_resp->data->eps_tflags;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	u32			credit = le32_to_cpu(
+					tx_resp->data->remaining_size_credit);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_urb	*maurb = container_of(tx_state,
+					struct mausb_urb, state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	mausb_dbg(mhcd, "%s: received transferResponse with sequence number %i"
+		" for transfer %i\n", __func__, SN, tx_resp->data->req_id);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	/* look for sequence number and/or request ID errors */
+	if (should_drop_txResp(ep_state, tx_state, tx_resp, MAUSB_OUT)) {
+		mausb_drop_packet(ep, tx_resp);
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		return payload_size;
+	}
+
+	switch (status) {
+	case SUCCESS:
+		/*  look for and acknowledge end of transfer */
+		if (ep_flags & MAUSB_PKT_TFLAG_EOT) {
+
+			spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+			host_send_ack(tx_state, MAUSB_OUT, ep_state,
+				 SUCCESS, SN);
+			spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+			ep_state->earliest_request_id =
+				mausb_req_id_add(
+					ep_state->earliest_request_id, 1);
+			ep_state->active_request_id =
+				mausb_req_id_add(
+					ep_state->active_request_id, 1);
+
+			tx_state->eot_detected = true;
+			tx_state->last_transfer_sn = SN;
+			maurb->urb->actual_length += tx_state->payload_size;
+		}
+
+		ep_state->earliest_unacked = SN + 1;
+		ep_state->rx_buf_size = credit - payload_size;
+		break;
+	case INVALID_REQUEST:
+		mausb_err(mhcd, "%s: status = INVALID_REQUEST\n", __func__);
+		/* TODO: start over with request number in packet */
+		break;
+	case DROPPED_PACKET:
+		mausb_err(mhcd, "%s: status = DROPPED_PACKET\n", __func__);
+		/* fallthrough, same as MISSING_SEQUENCE_NUMBER */
+	case MISSING_SEQUENCE_NUMBER:
+		mausb_err(mhcd, "%s: status = MISSING_SEQUENCE_NUMBER\n",
+		       __func__);
+		mausb_resend_multi_packets(ep, &ep->req_list,
+			le32_to_cpu(tx_resp->data->seq_num), irq_flags);
+		break;
+	case TRANSFER_PENDING:
+		mausb_err(mhcd, "%s: status = TRANSFER_PENDING\n", __func__);
+		/* TODO: reset transmission counter */
+		break;
+	case TRANSFER_EP_STALL:
+		printk(KERN_DEBUG "%s: status = TRANSFER_EP_STALL\n", __func__);
+		if (ep_flags & MAUSB_PKT_TFLAG_EOT) {
+			spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+			host_send_ack(tx_state, MAUSB_OUT, ep_state,
+				      TRANSFER_EP_STALL, SN);
+			spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+			tx_state->eot_detected = true;
+		}
+		break;
+	case TRANSFER_CANCELLED:
+		mausb_err(mhcd, "%s: status = TRANSFER_CANCELLED\n",
+			__func__);
+		break;
+	case TRANSFER_DATA_BUFFER_ERROR:
+		mausb_err(mhcd, "%s: status = TRANSFER_DATA_BUFFER_ERROR\n",
+		       __func__);
+		break;
+	default:
+		tx_state->transfer_error = true;
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	}
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return payload_size;
+}
+
+
+/* --------------------- Transfer interfaces ----------------------*/
+
+/**
+ * Interface called to initiate an IN or OUT transfer.
+ *
+ * @ep:     Host endpoint associated with transfer.
+ * @maurb:  maurb with payload to transfer.
+ *	    NOTE: one maurb maps to one transfer.
+ * @dir_in: Transfer direction. Set to one if IN (to host) or zero if OUT.
+ *
+ * Only one transfer can be in progress at a time for a particular endpoint.
+ * When a transfer is in progress, the tx_pending flag for that endpoint is set
+ * indicating that the endpoint is busy.
+ */
+int start_ma_transfer(struct mausb_host_ep *ep, struct mausb_urb *maurb,
+		int dir_in)
+{
+	int				     tx_size;
+	unsigned long			     irq_flags;
+	char				     *tx_type;
+	struct mausb_hcd		     *mhcd = mausb_host_ep_to_mahcd(ep);
+	const struct usb_endpoint_descriptor *ep_desc;
+
+	ep_desc = mausb_get_ep_des(ep);
+
+	switch (usb_endpoint_type(ep_desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		tx_type = "control";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		tx_type = "isochronous";
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		tx_type = "bulk";
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		tx_type = "interrupt";
+		break;
+	default:
+		tx_type = "unknown";
+	}
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* start a new transfer if there isn't one already in progress. */
+	if (ep->state.tx_pending == 0) {
+
+		ep->state.tx_pending = 1;
+		tx_size = maurb->urb->transfer_buffer_length;
+
+		/*
+		 * Set this transfer as active transfer for endpoint - this
+		 * is how we will get active transfer info when we receive
+		 * transferRequests.
+		 */
+		ep->active_transfer = maurb;
+
+		/* check to see if setup phase of control transfer */
+		if (mausb_control_xfer(maurb)) {
+			ep->state.seq_number = 0;
+			ep->state.earliest_unacked = 0;
+		}
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		/* initiate transfer by direction */
+		if (dir_in) {
+			mausb_dbg(mhcd, "%s: starting %s IN transfer for"
+				" endpoint %u\n", __func__, tx_type,
+				ep->ep_handle.ep_num);
+
+			host_init_IN_transfer(&maurb->state, ep, maurb);
+
+		} else {
+			mausb_dbg(mhcd, "%s: starting %s OUT transfer for"
+				" endpoint %u\n", __func__, tx_type,
+				ep->ep_handle.ep_num);
+
+			host_init_OUT_transfer(&maurb->state, ep, tx_size);
+			host_OUT_generate_txReqs(&maurb->state, &ep->state,
+				maurb);
+		}
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return -EINPROGRESS;
+}
+
+/**
+ * Interface called to give a transferResp to the host for IN transfers.
+ *
+ * @pkt:      transferResponse packet being received.
+ * @context:  Host endpoint associated with transfer.
+ *
+ * After an IN transfer is initiated, the host waits to receive transferResponse
+ * packets from the device-side endpoint. When a transferResponse is received,
+ * the host updates its transfer and endpoint states and copies the packet
+ * payload into the maurb buffer associated with the tranfer. If the device
+ * requests a transferAck packet, one is sent.
+ */
+int complete_IN_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int				urb_stat;
+	int				length = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_urb		*maurb;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_hcd		*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	tx_resp = mausb_pkt_from_ms_pkt_ep(pkt, ep, GFP_ATOMIC);
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mhcd = mausb_host_ep_to_mahcd(ep);
+	maurb = ep->active_transfer;
+
+	if (NULL == maurb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EINVAL;
+	}
+
+	tx_state = &maurb->state;
+	length = host_IN_txResp_rcvd(&ep->state, tx_state, tx_resp);
+
+	/* something went wrong in receiving the transferResp packet */
+	if (length < 0) {
+		mausb_err(mhcd, "%s: returning error %i\n", __func__, length);
+		return length;
+	}
+
+	/* look for end of transfer */
+	if (tx_state->eot_detected) {
+		ep->state.tx_pending = 0;
+
+		urb_stat = mausb_to_urb_status(tx_resp->data->common.pkt_status);
+		if (NULL != maurb)
+			mausb_unlink_giveback_urb(maurb, urb_stat);
+	}
+
+	/* if not end of transfer, set timer between packets */
+	else {
+		mod_timer(&ep->timer,
+			jiffies + msecs_to_jiffies(MAUSB_TRANSFER_KEEP_ALIVE));
+	}
+
+	return length;
+}
+
+/**
+ * Interface called to give the host a transferResp packet.
+ *
+ * @pkt:     transferResponse packet being received.
+ * @context: Host endpoint associated with transfer.
+ *
+ * For OUT transfers the host sends a series of transferRequest packets. A
+ * transferResponse packet is only sent by the device when a transferAck packet
+ * is requested by the host or the end of the transfer is reached.
+ */
+int complete_OUT_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int				urb_stat;
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_urb		*maurb;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_hcd		*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	tx_resp = mausb_pkt_from_ms_pkt_ep(pkt, ep, GFP_ATOMIC);
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mhcd = mausb_host_ep_to_mahcd(ep);
+	maurb = ep->active_transfer;
+
+	if (NULL == maurb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EFAULT;
+	}
+
+	tx_state = &maurb->state;
+
+	/*
+	 * Look for Retry flag in packet and resend requested packets
+	 * if we have them. Otherwise, pass packet on to receiving process.
+	 */
+	if (mausb_is_a_retry(ep, &ep->req_list, tx_resp) == false)
+		ret = host_OUT_txResp_rcvd(&ep->state, tx_state, tx_resp);
+
+	/* make sure we still have an active transfer */
+	if (!ep->active_transfer) {
+		mausb_cleanup_ma_packets(ep,
+			le32_to_cpu(tx_resp->data->seq_num),
+			tx_resp->data->req_id);
+		mausb_unlink_giveback_urb(maurb, -EINVAL);
+		return ret;
+	}
+
+	/* handle end of transfer */
+	if (tx_state->eot_detected) {
+		ep->state.tx_pending = 0;
+		mausb_cleanup_ma_packets(ep,
+			le32_to_cpu(tx_resp->data->seq_num),
+			tx_resp->data->req_id);
+		urb_stat = mausb_to_urb_status(
+			tx_resp->data->common.pkt_status);
+		mausb_unlink_giveback_urb(maurb, urb_stat);
+	}
+
+	return ret;
+}
+
+/*
+ * Receives transferRequest packets for control endpoint (ep0).
+ *
+ * @pkt:     transferResponse packet being received.
+ * @context: Host endpoint associated with transfer. This should always be
+ *	     control endpoint (ep0).
+ *
+ * Control transfers can be either IN or OUT. Transfer direction is parsed
+ * from the urb associated with the transfer, then the appropriate completion
+ * function is called.
+ */
+int complete_control_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int			dir_in = 0;
+	struct mausb_host_ep	*ep;
+	struct mausb_hcd	*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		printk(KERN_ERR "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	mhcd = mausb_host_ep_to_mahcd(ep);
+
+	if (NULL == mhcd) {
+		printk(KERN_ERR "%s: could not find MA USB HCD for endpoint"
+			" at 0x%p\n", __func__, ep);
+		return -EFAULT;
+	}
+
+	if (NULL == ep->active_transfer || NULL == ep->active_transfer->urb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EFAULT;
+	}
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	dir_in = usb_pipein(ep->active_transfer->urb->pipe);
+
+	if (dir_in)
+		complete_IN_transferRequest(pkt, context);
+	else
+		complete_OUT_transferRequest(pkt, context);
+
+	return 0;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_tx.c b/drivers/staging/mausb/drivers/mausb_tx.c
new file mode 100644
index 0000000..fb52ad1
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx.c
@@ -0,0 +1,318 @@
+/* Name:        mausb_tx.c
+ * Description: Common functions for both host and device media agnostic
+ *              transfers.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+#include "mausb_const.h"
+
+int mausb_transfer_data_pkt(struct mausb_pkt *pkt, struct mausb_host_ep *ep,
+		gfp_t mem_flags)
+{
+	int ret;
+
+	ret = mausb_pkt_fill_ms_pkt(pkt, mem_flags);
+	if (0 > ret)
+		return ret;
+
+	return mausb_transfer_packet(&pkt->pkt, &ep->tx_pair.to_ms);
+
+}
+EXPORT_SYMBOL(mausb_transfer_data_pkt);
+
+/**
+ * Opens an endpoint-specific connection between the media specific and media
+ * agnostic drivers in order to send and receive MA USB data packets.
+ *
+ * @drv:	  Media specific driver to establish connection with.
+ * @ep:  	  Host endpoint to be associated with this channel.
+ * @transfer_pkt: The call the MS driver should make when a packet is received.
+ */
+int mausb_add_data_channel(struct mausb_ms_drv *drv, struct mausb_host_ep *ep,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context))
+{
+	int				ret = 0;
+	struct mausb_transfer_pair	tx_pair;
+
+	matx_dbg("%s: adding channel for ep with handle %x\n", __func__,
+		ep->ep_handle.handle);
+
+	tx_pair.to_ma.transfer_packet = transfer_pkt;
+	tx_pair.to_ma.context = ep;
+	tx_pair.pkt_sent = NULL;
+	tx_pair.handle = ep->ep_handle.handle;
+
+	ret = drv->ops->add_transfer_pair(&tx_pair);
+
+	if (ret >= 0)
+		ep->tx_pair = tx_pair;
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_add_data_channel);
+
+/**
+ * Determines if conditions are met to complete a data transfer.
+ *
+ * @tx_state: State of transfer to be checked.
+ * @seq_num:  Sequence number to be compared to last sequence number in the
+ *	      transfer.
+ *
+ * Returns true if a transfer can be considered complete or false otherwise.
+ * Note that this does not differentiate between transfers that complete
+ * with and without an error.
+ */
+bool mausb_transfer_is_complete(struct mausb_transfer_state *tx_state,
+		u8 seq_num)
+{
+	bool complete = false;
+
+	if (!tx_state->transfer_error && tx_state->last_transfer_sn <= seq_num)
+		complete = true;
+
+	if (tx_state->transfer_error) {
+		matx_err("%s: transfer ending with error\n", __func__);
+		complete = true;
+	}
+
+	return complete;
+}
+EXPORT_SYMBOL(mausb_transfer_is_complete);
+
+/**
+ * Deletes packet from endpoint list and frees memory.
+ *
+ * @ep:	 Endpoint associated with packet to be dropped.
+ * @pkt: Packet to be dropped.
+ */
+void mausb_drop_packet(struct mausb_host_ep *ep, struct mausb_pkt *pkt)
+{
+	if (ep == NULL || pkt == NULL)
+		return;
+
+	list_del(&pkt->pkt_list);
+	mausb_free_pkt(pkt);
+
+	if (list_empty(&ep->req_list))
+		INIT_LIST_HEAD(&ep->req_list);
+
+	if (list_empty(&ep->resp_list))
+		INIT_LIST_HEAD(&ep->resp_list);
+}
+EXPORT_SYMBOL(mausb_drop_packet);
+
+/**
+ * Deletes all of the packets based on the sequence number.
+ *
+ * @ep:      Endpoint associated with transfer.
+ * @seq_num: The sequence number of the packets to delete. This will
+ *           delete all the packets with sequence numbers up to
+ *           (but not including) seq_num.
+ * @req_id:  The request ID of the packets to delete. This will
+ *           delete all the packets with request IDs up to
+ *           (but not including) req_id.
+ */
+void mausb_cleanup_ma_packets(struct mausb_host_ep *ep, u32 seq_num, u8 req_id)
+{
+	struct mausb_pkt *active, *next;
+
+	list_for_each_entry_safe(active, next, &ep->req_list, pkt_list) {
+		if (mausb_seq_num_lt(active->data->seq_num, seq_num) ||
+			mausb_req_id_lt(active->data->req_id, req_id))
+			mausb_drop_packet(ep, active);
+	}
+
+	list_for_each_entry_safe(active, next, &ep->resp_list, pkt_list) {
+		if (mausb_seq_num_lt(active->data->seq_num, seq_num) ||
+			mausb_req_id_lt(active->data->req_id, req_id))
+
+			mausb_drop_packet(ep, active);
+	}
+}
+EXPORT_SYMBOL(mausb_cleanup_ma_packets);
+
+/**
+ * Resend all packets starting from a given sequence number.
+ *
+ * @ep:		Endpoint associated with packets.
+ * @pkt_list: 	Head of list of packets to search.
+ * @seq_num: 	Sequence number of first packet to be sent.
+ *
+ * Returns 0 if at least one packet is sent, otherwise returns non-zero value.
+ * Note: the caller should be holding the endpoint's spinlock.
+ */
+int mausb_resend_multi_packets(struct mausb_host_ep *ep,
+		struct list_head *pkt_list,
+		u32 seq_num, unsigned long irq_flags)
+{
+	int			ret = -EINVAL;
+	struct mausb_pkt	*pkt;
+	int			i = 0;
+
+	list_for_each_entry(pkt, pkt_list, pkt_list) {
+
+		i++;
+		if (mausb_seq_num_gt_eq(pkt->data->seq_num, seq_num)) {
+			matx_dbg("%s: resending pkt %i\n", __func__,
+				pkt->data->seq_num);
+			pkt->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+			ret = 0;
+			mausb_transfer_data_pkt(pkt, ep, GFP_ATOMIC);
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_resend_multi_packets);
+
+/**
+ * Checks to see if a received packet is a retry and resends response packets
+ * (if found).
+ *
+ * @ep:		Endpoint associated with transfer.
+ * @pkt_list:	List of packets previously sent.
+ * @pkt:	Received packet.
+ *
+ * Returns true if received packet has the Retry flag set AND at least one
+ * response packet was found and sent. Returns false if the Retry flag not
+ * set or the Retry flag is set but no corresponding packets have been found.
+ */
+bool mausb_is_a_retry(struct mausb_host_ep *ep, struct list_head *pkt_list,
+		struct mausb_pkt *pkt)
+{
+	int			err	= 0;
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	if (pkt->common->ver_flags & MAUSB_PKT_FLAG_RETRY) {
+		matx_dbg("%s: packet is a retry\n", __func__);
+
+		/*
+		 * If received packet is a retry, look to see if we've
+		 * already generated the corresponding packets.
+		 */
+		err = mausb_resend_multi_packets(ep, pkt_list,
+			pkt->data->seq_num,
+				irq_flags);
+
+		/*
+		 * Only return true if packet is found, otherwise we might
+		 * miss responding to a packet we never received.
+		 */
+		if (err == 0)
+			return true;
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return false;
+}
+EXPORT_SYMBOL(mausb_is_a_retry);
+
+/**
+ * Called by timeout timer to start thread that handles error handling and
+ * packet resends.
+ *
+ * Used to avoid passing packets to a medium while in an interrupt context,
+ * which can be problematic for some mediums.
+ */
+void wake_timeout_thread(unsigned long _ep)
+{
+	struct mausb_host_ep	*ep = (struct mausb_host_ep *) _ep;
+	unsigned long		irq_flags;
+
+	matx_dbg("%s: timeout occurred!!!\n", __func__);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	ep->tx_timed_out = true;
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	wake_up_interruptible(&ep->host_ep_wq);
+}
+
+/**
+ * Fills packet fields based on the given EP. Also fills device fields.
+ */
+void mausb_fill_pkt_ep(struct mausb_pkt *pkt, struct mausb_host_ep *ma_ep)
+{
+	struct mausb_dev	*mausb_dev;
+	struct ma_dev		*ma_dev;
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	if (MAUSB_EP_HANDLE_ACTIVE != ma_ep->ep_handle_state) {
+		matx_warn("%s: endpoint handle not active\n", __func__);
+	}
+
+	pkt->common->ep_handle = ma_ep->ep_handle;
+	pkt->data->eps_tflags |= ma_ep->ep_handle_state;
+	/* TODO: set transfer Type */
+
+	mausb_dev = ma_ep->mausb_dev;
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	ma_dev = mausb_dev->ma_dev;
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	pkt->common->ma_dev_addr = ma_dev->ma_dev_addr;
+	pkt->common->mass_id = ma_dev->mass_id;
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+}
+EXPORT_SYMBOL(mausb_fill_pkt_ep);
+
+
diff --git a/drivers/staging/mausb/drivers/mausb_tx.h b/drivers/staging/mausb/drivers/mausb_tx.h
new file mode 100644
index 0000000..c876afc
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx.h
@@ -0,0 +1,129 @@
+/* Name:        mausb_tx.h
+ * Description:	header file for mausb_tx-device.c and mausb_tx-host.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define DEBUG
+
+#ifndef __MAUSB_TX_H
+#define __MAUSB_TX_H
+
+#include "mausb_mem.h"
+#include "mausb_pkt.h"
+
+#ifdef DEBUG
+#define matx_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define matx_dbg(format, arg...)
+#endif
+
+#define matx_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define matx_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* TODO: for now this is set to match gadget zero's buffer size, but
+ * eventually we need to get this value from the device instead of
+ * predefining it. */
+# define DEVICE_RX_BUF_SIZE 4096
+
+#define MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT 3000
+
+/* functions common to both host and device */
+int mausb_add_data_channel(struct mausb_ms_drv *drv, struct mausb_host_ep *ep,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context));
+
+int mausb_transfer_data_pkt(struct mausb_pkt *pkt, struct mausb_host_ep *ep,
+		gfp_t mem_flags);
+bool mausb_transfer_is_complete(struct mausb_transfer_state *tx_state,
+		u8 seq_num);
+void mausb_drop_packet(struct mausb_host_ep *ep, struct mausb_pkt *pkt);
+void mausb_cleanup_ma_packets(struct mausb_host_ep *ep, u32 seq_num,
+		u8 req_id);
+bool mausb_is_a_retry(struct mausb_host_ep *ep, struct list_head *pkt_list,
+		struct mausb_pkt *pkt);
+int mausb_resend_multi_packets(struct mausb_host_ep *ep,
+		struct list_head *pkt_list, u32 seq_num,
+		unsigned long irq_flags);
+void mausb_fill_pkt_ep(struct mausb_pkt *pkt, struct mausb_host_ep *ma_ep);
+
+/* transfer interface function declarations */
+int complete_control_transferRequest(struct ms_pkt *pkt, void *context);
+int complete_IN_transferRequest(struct ms_pkt *pkt, void *context);
+int complete_OUT_transferRequest(struct ms_pkt *pkt, void *context);
+int receive_ma_packet_control(struct ms_pkt *ms_pkt, void *context);
+int receive_ma_packet_IN(struct ms_pkt *ms_pkt, void *context);
+int receive_ma_packet_OUT(struct ms_pkt *ms_pkt, void *context);
+int start_ma_transfer(struct mausb_host_ep *ep, struct mausb_urb *maurb,
+		int dir_in);
+
+/* transfer state fucntion declarations */
+int device_OUT_deliver_payload(struct mausb_pkt *tx_req,
+		struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state);
+int device_OUT_send_txResp(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, u32 req_id,
+		u32 seq_num, int status, bool retry, bool eot, bool arq);
+void host_IN_txReq_transmit(struct mausb_pkt *tx_req, struct mausb_host_ep *ep,
+		struct mausb_transfer_state *tx_state);
+int device_IN_send_null_txResp(struct mausb_host_ep *ep, u8 req_id, int status);
+
+/* transfer timeout function declarations */
+void wake_timeout_thread(unsigned long _ep);
+int host_transfer_timeout(void *data);
+int device_transfer_timeout(void *data);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (7 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 20:42   ` [PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
  2014-11-04  9:00   ` [PATCH 00/10] MA USB drivers cover letter Bjørn Mork
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

Adds various scripts for building, loading and unloading the MA USB
drivers and a utility that can be used for connecting and disconnecting
the host and device drivers.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 .../staging/mausb/scripts/build_load_connect.sh    |  69 +++++++
 drivers/staging/mausb/scripts/load_gzero.sh        |   5 +
 drivers/staging/mausb/scripts/load_script.sh       | 125 +++++++++++++
 drivers/staging/mausb/scripts/modprobify.sh        |  10 ++
 drivers/staging/mausb/scripts/unload_all.sh        |  15 ++
 drivers/staging/mausb/scripts/unload_gzero.sh      |   5 +
 drivers/staging/mausb/tools/mausb-util/Makefile    |  14 ++
 drivers/staging/mausb/tools/mausb-util/README      |  30 ++++
 drivers/staging/mausb/tools/mausb-util/config.mk   |  17 ++
 .../staging/mausb/tools/mausb-util/src/Android.mk  |  13 ++
 .../staging/mausb/tools/mausb-util/src/Makefile    |  18 ++
 .../staging/mausb/tools/mausb-util/src/connect.c   |  72 ++++++++
 .../staging/mausb/tools/mausb-util/src/connect.h   |  22 +++
 drivers/staging/mausb/tools/mausb-util/src/mausb.c | 200 +++++++++++++++++++++
 drivers/staging/mausb/tools/mausb-util/src/mausb.h |  64 +++++++
 .../mausb/tools/mausb-util/src/mausb_ioctl.h       |  37 ++++
 drivers/staging/mausb/tools/mausb-util/src/utils.c |  94 ++++++++++
 17 files changed, 810 insertions(+)
 create mode 100644 drivers/staging/mausb/scripts/build_load_connect.sh
 create mode 100644 drivers/staging/mausb/scripts/load_gzero.sh
 create mode 100644 drivers/staging/mausb/scripts/load_script.sh
 create mode 100644 drivers/staging/mausb/scripts/modprobify.sh
 create mode 100644 drivers/staging/mausb/scripts/unload_all.sh
 create mode 100644 drivers/staging/mausb/scripts/unload_gzero.sh
 create mode 100644 drivers/staging/mausb/tools/mausb-util/Makefile
 create mode 100644 drivers/staging/mausb/tools/mausb-util/README
 create mode 100644 drivers/staging/mausb/tools/mausb-util/config.mk
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/Android.mk
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/Makefile
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/connect.c
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/connect.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb.c
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/tools/mausb-util/src/utils.c

diff --git a/drivers/staging/mausb/scripts/build_load_connect.sh b/drivers/staging/mausb/scripts/build_load_connect.sh
new file mode 100644
index 0000000..d055241
--- /dev/null
+++ b/drivers/staging/mausb/scripts/build_load_connect.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+side="invalid"
+mode="invalid"
+addr="invalid"
+
+while getopts "hdbtsa:" opt; do
+	case "$opt" in
+	h) side="-h"
+	   ;;
+	d) side="-d"
+	   ;;
+	b) side="-b"
+	   ;;
+	t) mode="-t"
+	   ;;
+	s) mode="-s"
+	   ;;
+	a) addr=$OPTARG
+	   ;;
+	esac
+done
+
+
+if [ "$side" == "invalid" ]
+then
+	echo $side
+	echo "please choose host (-h) or device (-d)"
+	exit
+fi
+
+if [ "$mode" == "invalid" ]
+then
+	echo $mode
+	echo "please choose tcp (-t) or snap (-s)"
+	exit
+fi
+
+if [ "$addr" == "invalid" ]
+then
+	echo $addr
+	echo "please enter a valid address (-a 1.2.3.4, -a 01:23:45:67:89:0a)"
+	exit
+fi
+
+
+cd ../
+# make clean && make
+make -j8
+cd drivers/
+
+wireshark -k -Y tcp -i eth0 &
+
+sudo ../scripts/load_script.sh $side $mode
+
+sudo cat /proc/modules | grep ma
+
+if [ "$mode" == "-s" ]
+then
+	echo "connecting mausb"
+	../tools/mausb-util/mausb -c -m llc -a $addr
+fi
+
+if [ "$mode" == "-t" ]
+then
+	echo "connecting mausb"
+	../tools/mausb-util/mausb -c -m ip -p 9001 -a $addr
+fi
+
diff --git a/drivers/staging/mausb/scripts/load_gzero.sh b/drivers/staging/mausb/scripts/load_gzero.sh
new file mode 100644
index 0000000..9266199
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_gzero.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+modprobe g_zero
+
+echo g_zero load process complete
\ No newline at end of file
diff --git a/drivers/staging/mausb/scripts/load_script.sh b/drivers/staging/mausb/scripts/load_script.sh
new file mode 100644
index 0000000..7c92afa
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_script.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+# This script is used for loading & unloading the mausb_driver
+
+# note: this script must be run with root priviledge (for the modprobes)
+
+side="invalid"
+mode="invalid"
+load="load"
+
+# Determine weather to load a host or device in TCP mode or snap mode
+while getopts "hdbtslu" opt; do
+	case "$opt" in
+	h) side="host"
+	   ;;
+	d) side="device"
+	   ;;
+	b) side="both"
+	   ;;
+	t) mode="tcp"
+	   ;;
+	s) mode="snap"
+	   ;;
+	l) load="load"
+	   ;;
+	u) load="unload"
+	   ;;
+	esac
+done
+
+if [ "$side" == "invalid" ]
+then
+	echo $side
+	echo "please choose host (-h) or device (-d)"
+	exit
+fi
+
+if [ "$mode" == "invalid" ]
+then
+	echo $mode
+	echo "please choose a tcp (-t) or snap (-s)"
+	exit
+fi
+
+
+
+if [ "$load" == "load" ]
+then
+	# copy the LKM into the module library
+	pushd $(dirname $0)
+	cp ../drivers/*.ko /lib/modules/$(uname -r)/kernel/drivers/usb/
+	popd
+
+	# depmod so the kernel can figure out its dependacies
+	depmod -A
+
+	# open the file for ioctl calls
+	mknod /dev/mausb c 100 0
+
+	modprobe_flags=""
+
+elif [ "$load" == "unload" ]
+then
+	# unload the drivers instead of loading them
+	modprobe_flags="-r"
+
+fi
+
+
+
+# load the drivers
+
+if [ "$mode" == "tcp" ] && [ "$load" == "load" ]
+then
+	modprobe $modprobe_flags matcp_core
+
+elif [ "$mode" == "snap" ]
+then
+	modprobe $modprobe_flags masnap_core
+fi
+
+
+if [ "$side" == "device" ] || [ "$side" == "both" ]
+then
+	if [ "$load" == "load" ]
+	then
+		modprobe $modprobe_flags maudc
+	fi
+
+	modprobe $modprobe_flags g_zero
+
+	if [ "$mode" == "tcp" ]
+	then
+		modprobe $modprobe_flags matcp_dev
+
+	elif [ "$mode" == "snap" ]
+	then
+		modprobe $modprobe_flags masnap_dev
+	fi
+fi
+
+if [ "$side" == "host" ] || [ "$side" == "both" ]
+then
+	if [ "$load" == "load" ]
+	then
+		modprobe $modprobe_flags mausb
+	fi
+
+	if [ "$mode" == "tcp" ]
+	then
+		modprobe $modprobe_flags matcp_host
+
+	elif [ "$mode" == "snap" ]
+	then
+		modprobe $modprobe_flags masnap_host
+	fi
+
+fi
+
+if [ "$load" == "unload" ]
+then
+	modprobe $modprobe_flags maudc
+	modprobe $modprobe_flags mausb
+fi
+
+echo "$load mausb $side $mode driver complete"
diff --git a/drivers/staging/mausb/scripts/modprobify.sh b/drivers/staging/mausb/scripts/modprobify.sh
new file mode 100644
index 0000000..b5f16ab
--- /dev/null
+++ b/drivers/staging/mausb/scripts/modprobify.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+
+# note: this scripted needs to be run as a superuser to work
+
+# copy the LKM into the module library
+cp ./*.ko /lib/modules/$(uname -r)/kernel/drivers/usb/
+
+# depmod so the kernel can figure out its dependacies
+depmod -A
diff --git a/drivers/staging/mausb/scripts/unload_all.sh b/drivers/staging/mausb/scripts/unload_all.sh
new file mode 100644
index 0000000..26af664
--- /dev/null
+++ b/drivers/staging/mausb/scripts/unload_all.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+modprobe -r g_zero
+
+echo g_zero unload process complete
+
+./../tools/mausb-util/mausb -d
+
+echo mausb disconnect complete
+
+rmmod matcp_dev
+rmmod matcp_host
+rmmod matcp_core
+rmmod maudc
+rmmod mausb
diff --git a/drivers/staging/mausb/scripts/unload_gzero.sh b/drivers/staging/mausb/scripts/unload_gzero.sh
new file mode 100644
index 0000000..e506b2d
--- /dev/null
+++ b/drivers/staging/mausb/scripts/unload_gzero.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+modprobe -r g_zero
+
+echo g_zero unload process complete
\ No newline at end of file
diff --git a/drivers/staging/mausb/tools/mausb-util/Makefile b/drivers/staging/mausb/tools/mausb-util/Makefile
new file mode 100644
index 0000000..abd5fe0
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/Makefile
@@ -0,0 +1,14 @@
+include config.mk
+
+.PHONY: $(BINARY_NAME) all clean
+
+all: $(BINARY_NAME)
+
+$(BINARY_NAME):
+	$(MAKE) -C src/
+	cp -rf src/$(BINARY_NAME) .
+
+
+clean:
+	$(MAKE) -C src/ clean
+	rm -rf $(BINARY_NAME) *~
diff --git a/drivers/staging/mausb/tools/mausb-util/README b/drivers/staging/mausb/tools/mausb-util/README
new file mode 100644
index 0000000..967f00e
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/README
@@ -0,0 +1,30 @@
+#    #   ##   #    #  ####  #####     #    # ##### # #      # ##### #   #
+##  ##  #  #  #    # #      #    #    #    #   #   # #      #   #    # #
+# ## # #    # #    #  ####  #####     #    #   #   # #      #   #     #
+#    # ###### #    #      # #    #    #    #   #   # #      #   #     #
+#    # #    # #    # #    # #    #    #    #   #   # #      #   #     #
+#    # #    #  ####   ####  #####      ####    #   # ###### #   #     #
+
+
+Author: Aymen Zayet
+License: GPL2
+Version: 0.1
+
+1. Description
+--------------
+This tool includes many commands that help to test / debug the MAUSB devices.
+mausb bin provides to the host a way to connect and disconnect from the MAUSB device.
+
+2. Usage
+--------
+on the device side , run :
+>> mausb --mode ip --connect --addr <<HOST_IP_ADDR>>
+
+from the host side, run :
+>> mausb --mode ip --connect --addr 0.0.0.0
+
+3. Documentation
+----------------
+
+4. Miscellaneous
+----------------
diff --git a/drivers/staging/mausb/tools/mausb-util/config.mk b/drivers/staging/mausb/tools/mausb-util/config.mk
new file mode 100644
index 0000000..ea5f1de
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/config.mk
@@ -0,0 +1,17 @@
+SRCDIR          = $(shell pwd)
+DESTDIR         = /usr/local/bin
+
+CC              = gcc
+CFLAGS          = -g -ggdb -D __DEBUG
+LDFLAGS         =
+SHELL           = /bin/sh
+#CFLAGS         = -O2 -fomit-frame-pointer
+
+PROJECT_NAME    = mausb
+PROJECT_VERSION = 0.1
+
+BINARY_NAME     = $(PROJECT_NAME)
+
+SOURCE_FILES    = utils.c connect.c mausb.c
+
+OBJECT_FILES    = $(SOURCE_FILES:.c=.o)
diff --git a/drivers/staging/mausb/tools/mausb-util/src/Android.mk b/drivers/staging/mausb/tools/mausb-util/src/Android.mk
new file mode 100644
index 0000000..881c5fc
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -Wall -g
+LOCAL_LDFLAGS +=
+LOCAL_LDLIBS += -lpthread -lm -ldl
+LOCAL_SRC_FILES:= \
+	mausb.c \
+	utils.c \
+	connect.c
+LOCAL_C_INCLUDES += linux/modules/ma-usb/drivers
+LOCAL_MODULE := mausb
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
diff --git a/drivers/staging/mausb/tools/mausb-util/src/Makefile b/drivers/staging/mausb/tools/mausb-util/src/Makefile
new file mode 100644
index 0000000..deb98a6
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/Makefile
@@ -0,0 +1,18 @@
+include ../config.mk
+
+all: $(BINARY_NAME)
+
+$(BINARY_NAME): $(OBJECT_FILES)
+	@echo -n "(LD)" $@ " "
+	@$(CC) $(LDFLAGS) $(CFLAGS) $^ -o $@
+	@echo OK
+
+%.o: %.c
+	@echo -n "(CC)" $@ " "
+	@$(CC) $(CFLAGS) -c $< -o $@
+	@echo OK
+
+clean:
+	rm -rf *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c .tmp_versions Module*.symv\
+ers
+	rm -f $(BINARY_NAME) *~
\ No newline at end of file
diff --git a/drivers/staging/mausb/tools/mausb-util/src/connect.c b/drivers/staging/mausb/tools/mausb-util/src/connect.c
new file mode 100644
index 0000000..3c659ac
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/connect.c
@@ -0,0 +1,72 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "mausb.h"
+
+int set_ipv4_addr(mausb_t *config)
+{
+	char buf1[128] = {0};
+	char buf2[128] = {0};
+	printf("%s: setting ip address\n", __func__);
+	sprintf(buf1, "%u", config->ip);
+	sprintf(buf2, "%s", config->ip_addr);
+	if (0 <= ioctl(config->device, IOCTL_SET_IP_DECIMAL, buf1))
+		if (0 <= ioctl(config->device, IOCTL_SET_IP, buf2))
+			return 0;
+	return errno;
+}
+
+int set_mac_addr(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: setting mac address\n", __func__);
+	memcpy(buf, config->mac, 6);
+	if (0 <= ioctl(config->device, IOCTL_SET_MAC, buf)) {
+		printf("Msg from kernel space : mac %s set successfully\n",
+		       (char *)buf);
+		return 0;
+	}
+	return errno;
+}
+int set_port(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: setting port\n", __func__);
+	sprintf(buf, "%u", config->port);
+	if (0 <= ioctl(config->device, IOCTL_SET_PORT, buf))
+		return 0;
+	return errno;
+}
+
+int connect_device(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: connecting device\n", __func__);
+	if (0 <= ioctl(config->device, IOCTL_GADGET_C, buf))
+		return 0;
+	return errno;
+}
+
+int disconnect_device(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: disconnecting device\n", __func__);
+	if (0 <= ioctl(config->device, IOCTL_GADGET_D, buf))
+		return 0;
+	return errno;
+}
diff --git a/drivers/staging/mausb/tools/mausb-util/src/connect.h b/drivers/staging/mausb/tools/mausb-util/src/connect.h
new file mode 100644
index 0000000..30bd1c5
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/connect.h
@@ -0,0 +1,22 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CONNECT_H_
+#define CONNECT_H_
+
+#endif /* CONNECT_H_ */
diff --git a/drivers/staging/mausb/tools/mausb-util/src/mausb.c b/drivers/staging/mausb/tools/mausb-util/src/mausb.c
new file mode 100644
index 0000000..d323c03
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/mausb.c
@@ -0,0 +1,200 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mausb.h"
+
+
+
+static struct option l_opts[] = {
+	/* no_argument options */
+	{"help", no_argument, 0, 'h'},
+	{"verbose", no_argument, 0, 'v'},
+	{"connect", no_argument, 0, 'c'},
+	{"disconnect", no_argument, 0, 'd'},
+
+	/* required_argument options */
+	{"addr", required_argument, 0, 'a'},
+	{"port", required_argument, 0, 'p'},
+	{"mode", required_argument, 0, 'm'},
+
+	/* end */
+	{0, 0, 0, 0},
+};
+
+static void usage(const char *this)
+{
+	fprintf(stderr,
+		"Usage: "
+		"\t%s [[options]] command"
+		"\n\t\t [--help/-h] show this help"
+		"\n\t\t [--verbose/-h] Add more trace about what's going on"
+		"\n\t\t [--mode/-m] mausb mode to be used : ip (default) or llc"
+		"\n\t\t [--connect/-c] connect to mausb device"
+		"\n\t\t [--disconnect/-d] disconnect from mausb device"
+		"\n\t\t [--port/-p] set the port number in case of tcp connection"
+		"\n\t\t [--addr/-a] ip or mac address depending on the given mode"
+		"\n", this);
+}
+
+static int check_config(void)
+{
+	int ret;
+
+	if (config.cmd == disconnect)
+		return 0;
+
+	switch (config.mode) {
+	case ip:
+		ret = !config.port;
+		break;
+	case llc:
+		ret = !config.mac;
+		break;
+	default:
+		ret = !! config.mode;
+	}
+
+	return ((config.cmd > max_command) ||
+		(config.mode > supported_mode) ||
+		ret);
+}
+
+static void print_config(void)
+{
+	return;
+}
+
+static int process_options(int argc, char **argv)
+{
+	int option;
+
+	memset(&config, 0, sizeof(mausb_t));
+        config.mode = ip;
+	while ((option = getopt_long(argc, argv, "hfp:a:cdvm:", l_opts, NULL)) != EOF) {
+		switch(option) {
+		case 'h': // help
+			usage(argv[0]);
+			exit(0);
+			break;
+
+		case 'v': // verbose
+			config.verbose = 1;
+			break;
+ 
+		case 'c': // connect
+			config.cmd = connect;
+			break;
+
+		case 'd': // disconnect
+			config.cmd = disconnect;
+			break;
+
+		case 'm': // mode
+			if (strlen(optarg) == 3 && !strncmp(optarg, "llc", 3))
+				config.mode = llc;
+			else if (strlen(optarg) == 2 && !strncmp(optarg, "ip", 2))
+				config.mode = ip;
+			else {
+				fprintf(stderr, "could not determine mode\n");
+				goto err_options;
+			}
+			break;
+
+		case 'a': // addr
+			if (config.mode == llc) {
+				if (MACADDR_STR_SIZE != strlen(optarg))
+					goto err_options;
+				if (get_mac_address(optarg, config.mac))
+					goto err_options;
+			} else {
+				if (strlen(optarg) >= IPADDR_MAX)
+					goto err_options;
+				if (convert_ipv4_to_uint32(optarg, &config.ip))
+					goto err_options;
+				strcpy(config.ip_addr, optarg);
+			}
+			break;
+
+		case 'p': // port
+			config.port = atoi(optarg);
+			break;
+
+		default:
+			fprintf(stderr, "invalid option %c\n", option);
+			goto err_options;
+			break;
+		}
+	}
+
+	if (check_config()) {
+		fprintf(stderr, "check_config() failed\n");
+		goto err_options;
+	}
+
+	if (config.verbose)
+		print_config();
+
+	return 0;
+
+err_options:
+	usage(argv[0]);
+	return -1;
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	if (ret = process_options(argc, argv))
+		goto error;
+
+	printf("progran terminated successfully ip %x %s %d\n", config.ip,
+	       config.ip_addr, config.port);
+
+	ret = config.device = open(MAUSB_DEVICE, 0);
+	if (ret < 0) {
+		fprintf(stderr, "cannot open device %d\n", ret);
+		goto error;
+	}
+
+	switch(config.cmd) {
+	case connect:
+		if (config.verbose)
+			printf("connecting to %s port %u\n", config.ip_addr, config.port);
+		if (config.mode == llc) {
+			if (ret = set_mac_addr(&config))
+				goto close_device;
+		} else {
+			if (ret = set_ipv4_addr(&config))
+				goto close_device;
+			if (ret = set_port(&config))
+				goto close_device;
+		}
+		if  (ret = connect_device(&config))
+			goto close_device;
+		break;
+	case disconnect:
+		disconnect_device(&config);
+		break;
+	}
+close_device:
+	close(config.device);
+error:
+	return ret;
+}
diff --git a/drivers/staging/mausb/tools/mausb-util/src/mausb.h b/drivers/staging/mausb/tools/mausb-util/src/mausb.h
new file mode 100644
index 0000000..547bc92a
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/mausb.h
@@ -0,0 +1,64 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef MAUSB_H_
+#define MAUSB_H_
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include "connect.h"
+#include "mausb_ioctl.h"
+
+#define MAUSB_DEVICE "/dev/mausb"
+#define IPADDR_MAX 16
+#define MACADDR_STR_SIZE 17 /* excluding null termination char */
+
+typedef enum {
+	connect,
+	disconnect,
+	max_command,
+} mausb_cmd;
+
+typedef enum {
+	ip,
+	llc,
+	supported_mode,
+} mausb_mode;
+
+typedef struct {
+	int device;		       // file descriptor of the mausb device
+	char verbose;		       // is verbose mode enabled
+	mausb_cmd cmd;		       // keep the requested command to execute
+	uint32_t ip;		       // ip address of the device in case of ip mode
+	char ip_addr[IPADDR_MAX];      // ip address given in cmdline (x.x.x.x)
+	uint8_t mac[6];		       // mac address (aa:bb:cc:dd:ee:ff)
+	uint32_t port;		       // ip port number in case of ip mode
+	mausb_mode mode;	       // default is ip
+} mausb_t;
+
+mausb_t config;
+int convert_ipv4_to_uint32(char *, uint32_t *);
+
+int get_mac_address(char *, uint8_t *);
+#endif /* MAUSB_H_ */
diff --git a/drivers/staging/mausb/tools/mausb-util/src/mausb_ioctl.h b/drivers/staging/mausb/tools/mausb-util/src/mausb_ioctl.h
new file mode 100644
index 0000000..1cf8d50
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/mausb_ioctl.h
@@ -0,0 +1,37 @@
+#ifndef MAUSB_IOCTL_H
+#define MAUSB_IOCTL_H
+
+#define BUFFER 80
+#define DRIVER_VERSION "Alpha 0.0.25"
+#define MAJOR_NUM 100
+
+/* These define the ioctl functions that can be used */
+#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
+
+#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
+
+#define IOCTL_GET_VRSN _IOR(MAJOR_NUM, 2, char *)
+
+#define IOCTL_GET_NAME _IOR(MAJOR_NUM, 3, char *)
+
+#define IOCTL_GADGET_C _IOR(MAJOR_NUM, 4, char *)
+
+#define IOCTL_GADGET_D _IOR(MAJOR_NUM, 5, char *)
+
+#define IOCTL_MED_DELAY _IOR(MAJOR_NUM, 6, char *)
+
+#define IOCTL_SET_IP _IOR(MAJOR_NUM, 7, char *)
+
+#define IOCTL_SET_PORT _IOR(MAJOR_NUM, 8, char *)
+
+#define IOCTL_SET_IP_DECIMAL _IOR(MAJOR_NUM, 9, char *)
+
+#define IOCTL_SET_MAC _IOR(MAJOR_NUM, 10, char *)
+
+/* This is the location where the device file will be created. It is used to
+ * read/write to in order to communicate to and from the device */
+#define DEVICE_FILE_NAME "/dev/mausb"
+
+#define ETH_ALEN 6
+
+#endif
diff --git a/drivers/staging/mausb/tools/mausb-util/src/utils.c b/drivers/staging/mausb/tools/mausb-util/src/utils.c
new file mode 100644
index 0000000..1bb5063
--- /dev/null
+++ b/drivers/staging/mausb/tools/mausb-util/src/utils.c
@@ -0,0 +1,94 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "mausb.h"
+
+int convert_ipv4_to_uint32(char *addr, uint32_t *ipnum)
+{
+	uint8_t digits[4];
+	int i, j = 0;
+        char ip[64];
+
+	if (addr == NULL)
+		goto input_err;
+
+	strncpy(ip, addr, strlen(addr)+1);
+	i = strlen(ip);
+	memset(digits, 0, 4);
+
+	if (IPADDR_MAX < strlen(ip))
+		goto input_err;
+
+again:
+	while (i-1 && ip[--i - 1] != '.');
+	if (i-1) {
+		ip[i-1] = '\0';
+		digits[j++] = atoi(ip+i);
+		goto again;
+	} else
+		digits[j++] = atoi(ip);
+
+	*ipnum = digits[3] << 24 |
+		digits[2] << 16 |
+		digits[1] << 8 |
+		digits[0] << 0;
+
+	return 0;
+
+input_err:
+	return -1;
+}
+
+
+int get_mac_address(char *addr, uint8_t *out)
+{
+
+	uint8_t digits[6];
+	int i, j = 0;
+	char mac[64];
+
+	if (addr == NULL)
+		goto input_err;
+
+	strncpy(mac, addr, strlen(addr)+1);
+	i = strlen(mac);
+	memset(digits, 0, 6);
+
+	if (MACADDR_STR_SIZE != strlen(mac))
+		goto input_err;
+
+again:
+	while (i-1 && mac[--i - 1] != ':');
+	if (i-1) {
+		mac[i-1] = '\0';
+		digits[j++] = strtol(mac+i, NULL, 16);
+		goto again;
+	} else
+		digits[j++] = strtol(mac, NULL, 16);
+
+	for (i = 0; i < 6; i++) {
+                printf("[%d]=0x%x ", i, digits[i]);
+		out[5-i] = digits[i];
+        }
+
+        printf("\n");
+	return 0;
+
+input_err:
+	return -1;
+}
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 10/10] added kernel build, configuration, and TODO files
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (8 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
@ 2014-11-03 20:42   ` Stephanie Wallick
  2014-11-03 21:22     ` Greg KH
  2014-11-03 21:24     ` Greg KH
  2014-11-04  9:00   ` [PATCH 00/10] MA USB drivers cover letter Bjørn Mork
  10 siblings, 2 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-03 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, devel, Sean O. Stalley

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/Kconfig                |  2 ++
 drivers/staging/Makefile               |  1 +
 drivers/staging/mausb/Kconfig          | 16 ++++++++++++++++
 drivers/staging/mausb/Makefile         |  3 +++
 drivers/staging/mausb/TODO             | 14 ++++++++++++++
 drivers/staging/mausb/drivers/Kconfig  | 34 ++++++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/Makefile | 20 ++++++++++++++++++++
 7 files changed, 90 insertions(+)
 create mode 100644 drivers/staging/mausb/Kconfig
 create mode 100644 drivers/staging/mausb/Makefile
 create mode 100644 drivers/staging/mausb/TODO
 create mode 100644 drivers/staging/mausb/drivers/Kconfig
 create mode 100644 drivers/staging/mausb/drivers/Makefile

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 35b494f..f57621b 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,6 +24,8 @@ menuconfig STAGING
 
 if STAGING
 
+source "drivers/staging/mausb/Kconfig"
+
 source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e66a5db..7615c85 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_GS_FPGABOOT)	+= gs_fpgaboot/
 obj-$(CONFIG_BT_NOKIA_H4P)	+= nokia_h4p/
 obj-$(CONFIG_CRYPTO_SKEIN)	+= skein/
 obj-$(CONFIG_UNISYSSPAR)	+= unisys/
+obj-$(CONFIG_MAUSB)		+= mausb/
diff --git a/drivers/staging/mausb/Kconfig b/drivers/staging/mausb/Kconfig
new file mode 100644
index 0000000..095c08b
--- /dev/null
+++ b/drivers/staging/mausb/Kconfig
@@ -0,0 +1,16 @@
+
+menuconfig MAUSB
+	bool "MA USB drivers"
+	depends on USB
+	---help---
+	  This option allows you to select from the various MA USB
+	  drivers. Note that a media-specific driver (e.g. tcp or SNAP)
+	  is needed in addition to the media agnostic host or device driver.
+
+
+if MAUSB
+
+source "drivers/staging/mausb/drivers/Kconfig"
+
+endif
+
diff --git a/drivers/staging/mausb/Makefile b/drivers/staging/mausb/Makefile
new file mode 100644
index 0000000..b559322
--- /dev/null
+++ b/drivers/staging/mausb/Makefile
@@ -0,0 +1,3 @@
+#obj-$(CONFIG_MAUSB) += drivers/
+obj-y += drivers/
+
diff --git a/drivers/staging/mausb/TODO b/drivers/staging/mausb/TODO
new file mode 100644
index 0000000..dd124ed
--- /dev/null
+++ b/drivers/staging/mausb/TODO
@@ -0,0 +1,14 @@
+TODO:
+	- checkpatch.pl cleanups
+	- address miscellaneous "TODO" statements in code
+	- add support for multiple media agnostic (MA) devices
+	- add/improve support for unimplemented packet types
+	- handle errors and failure with more grace and less crash
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and cc:
+
+	Sean Stalley <sean.stalley@intel.com>
+	Stephanie Wallick <stephanie.s.wallick@intel.com>
+
+
+
diff --git a/drivers/staging/mausb/drivers/Kconfig b/drivers/staging/mausb/drivers/Kconfig
new file mode 100644
index 0000000..9e12e22
--- /dev/null
+++ b/drivers/staging/mausb/drivers/Kconfig
@@ -0,0 +1,34 @@
+config MA_CORE
+	tristate "MA USB core"
+	---help---
+	  This builds ma_core module.
+
+config MAUSB_HOST
+	tristate "MA USB host"
+	depends on MA_CORE
+	---help---
+	  This builds MA USB host driver module.
+
+config MAUSB_DEVICE
+	tristate "MA USB device"
+	depends on MA_CORE && USB_GADGET
+	---help---
+	  This builds MA USB device driver module.
+
+config MATCP_CORE
+	tristate "MA USB tcp core"
+	---help---
+	  This builds tcp_core module.
+
+config MATCP_HOST
+	tristate "MA USB host tcp"
+	depends on MATCP_CORE
+	---help---
+	  This builds tcp_host module.
+
+config MATCP_DEVICE
+	tristate "MA USB device tcp"
+	depends on MATCP_CORE
+	---help---
+	  This builds tcp_dev module.
+
diff --git a/drivers/staging/mausb/drivers/Makefile b/drivers/staging/mausb/drivers/Makefile
new file mode 100644
index 0000000..a38491e
--- /dev/null
+++ b/drivers/staging/mausb/drivers/Makefile
@@ -0,0 +1,20 @@
+#MY_CFLAGS =-g -O0 -DEBUG_OUTPUT
+
+obj-$(CONFIG_MA_CORE) += ma_core.o
+ma_core-y := mausb_pkt.o mausb_tx.o mausb_msapi.o mausb_mem.o mausb_mgmt.o
+
+obj-$(CONFIG_MAUSB_HOST) += mausb.o
+mausb-y := mausb_hcd.o mausb_hub.o mausb_tx-host.o mausb_mem-host.o
+
+obj-$(CONFIG_MAUSB_DEVICE) += maudc.o
+maudc-y := mausb_udc.o mausb_tx-device.o
+
+obj-$(CONFIG_MATCP_HOST) += matcp_host.o
+matcp_host-y := mausb_tcp-host.o
+
+obj-$(CONFIG_MATCP_DEVICE) += matcp_dev.o
+matcp_dev-y := mausb_tcp-device.o
+
+obj-$(CONFIG_MATCP_CORE) += matcp_core.o
+matcp_core-y := mausb_tcp.o mausb_ioctl.o
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
@ 2014-11-03 21:18     ` Greg KH
  2014-11-03 23:47       ` steph
  2014-11-03 21:21     ` Greg KH
  1 sibling, 1 reply; 54+ messages in thread
From: Greg KH @ 2014-11-03 21:18 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> +#define DEBUG

I doubt you want this in the driver enabled by default :(


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
  2014-11-03 21:18     ` Greg KH
@ 2014-11-03 21:21     ` Greg KH
  2014-11-04  0:04       ` steph
  1 sibling, 1 reply; 54+ messages in thread
From: Greg KH @ 2014-11-03 21:21 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> +EXPORT_SYMBOL(mausb_register_ms_driver);

EXPORT_SYMBOL_GPL()?  I have to ask...

> +static int mausb_hcd_init(void)
> +{
> +	int ret;
> +
> +	/* register HCD driver */
> +	ret = platform_driver_register(&mausb_driver);

Why is this a platform driver?  How does this relate to platform
hardware?

> +	if (ret < 0) {
> +		printk(KERN_DEBUG "%s: failed to register HC driver: "
> +			" error number %d\n", __func__, ret);

pr_err()?

return here, that way you don't need:

> +	} else {

This indentation.

> +		/* register HCD device */
> +		ret = platform_device_register(&mausb_pdev);

But again, why is this a platform device?  What platform resources does
it have / require?

> +
> +		if (ret < 0) {
> +			printk(KERN_DEBUG "%s: failed to register HC device:"
> +				"error number %d\n", __func__, ret);

pr_err()?

> +			platform_driver_unregister(&mausb_driver);
> +		} else {
> +			/* direct the release function (for exiting) */
> +			mausb_pdev.dev.release = &mausb_dev_release;

That seems like a serious hack, why do you need to do this in this
manner?

> +
> +			if (ret < 0) {
> +				printk(KERN_DEBUG "failed to register HC"
> +					" chardev: error number %d\n", ret);

pr_err()?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 10/10] added kernel build, configuration, and TODO files
  2014-11-03 20:42   ` [PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
@ 2014-11-03 21:22     ` Greg KH
  2014-11-03 21:24     ` Greg KH
  1 sibling, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-03 21:22 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 12:42:57PM -0800, Stephanie Wallick wrote:
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/Makefile
> @@ -0,0 +1,20 @@
> +#MY_CFLAGS =-g -O0 -DEBUG_OUTPUT

Please remove that line, it's not ever to be used.



^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 10/10] added kernel build, configuration, and TODO files
  2014-11-03 20:42   ` [PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
  2014-11-03 21:22     ` Greg KH
@ 2014-11-03 21:24     ` Greg KH
       [not found]       ` <54591319.c3b5440a.7374.5f85SMTPIN_ADDED_BROKEN@mx.google.com>
  1 sibling, 1 reply; 54+ messages in thread
From: Greg KH @ 2014-11-03 21:24 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 12:42:57PM -0800, Stephanie Wallick wrote:
> --- /dev/null
> +++ b/drivers/staging/mausb/TODO
> @@ -0,0 +1,14 @@
> +TODO:
> +	- checkpatch.pl cleanups

Is this still true?

And why does this need to be a staging driver?  What's wrong with making
it a "real" driver now?


> +	- address miscellaneous "TODO" statements in code
> +	- add support for multiple media agnostic (MA) devices
> +	- add/improve support for unimplemented packet types
> +	- handle errors and failure with more grace and less crash
> +
> +Please send patches to Greg Kroah-Hartman <greg@kroah.com> and cc:

You didn't use this email address...

> +	Sean Stalley <sean.stalley@intel.com>
> +	Stephanie Wallick <stephanie.s.wallick@intel.com>
> +

Just make a MAINTAINERS entry please for this info.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-03 21:18     ` Greg KH
@ 2014-11-03 23:47       ` steph
  0 siblings, 0 replies; 54+ messages in thread
From: steph @ 2014-11-03 23:47 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 01:18:16PM -0800, Greg KH wrote:
> On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> > +#define DEBUG
> 
> I doubt you want this in the driver enabled by default :(
> 

Thank you for catching, will remove in the next patch version.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-03 21:21     ` Greg KH
@ 2014-11-04  0:04       ` steph
  2014-11-04  0:13         ` Greg KH
  0 siblings, 1 reply; 54+ messages in thread
From: steph @ 2014-11-04  0:04 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 01:21:39PM -0800, Greg KH wrote:
> On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> > +EXPORT_SYMBOL(mausb_register_ms_driver);
> 
> EXPORT_SYMBOL_GPL()?  I have to ask...
>
The source is dual-licenced under BSD and GPL. It was our understanding
that dual-licensed should use EXPORT_SYMBOL() instead. Is that wrong?
 
> > +static int mausb_hcd_init(void)
> > +{
> > +	int ret;
> > +
> > +	/* register HCD driver */
> > +	ret = platform_driver_register(&mausb_driver);
> 
> Why is this a platform driver?  How does this relate to platform
> hardware?
> 
The driver doesn't require platform resources. It looks like a host
controller driver but communicates over the network instead of to
a physical host controller. There is no MA USB-specific hardware.

Should we use a struct device instead of a struct platform_device?

> > +	if (ret < 0) {
> > +		printk(KERN_DEBUG "%s: failed to register HC driver: "
> > +			" error number %d\n", __func__, ret);
> 
> pr_err()?
>
Will change all printk() to pr_err() in next patch.
 
> return here, that way you don't need:
> 
> > +	} else {
> 
> This indentation.
> 
Will fix in next patch.

> > +		/* register HCD device */
> > +		ret = platform_device_register(&mausb_pdev);
> 
> But again, why is this a platform device?  What platform resources does
> it have / require?
> 
See above.

> > +
> > +		if (ret < 0) {
> > +			printk(KERN_DEBUG "%s: failed to register HC device:"
> > +				"error number %d\n", __func__, ret);
> 
> pr_err()?
> 
See above.

> > +			platform_driver_unregister(&mausb_driver);
> > +		} else {
> > +			/* direct the release function (for exiting) */
> > +			mausb_pdev.dev.release = &mausb_dev_release;
> 
> That seems like a serious hack, why do you need to do this in this
> manner?
> 
This will go away when we get rid of the platform device.

> > +
> > +			if (ret < 0) {
> > +				printk(KERN_DEBUG "failed to register HC"
> > +					" chardev: error number %d\n", ret);
> 
> pr_err()?
>
See above.
 
> thanks,
> 
> greg k-h

Thanks,
Stephanie

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-04  0:04       ` steph
@ 2014-11-04  0:13         ` Greg KH
  2014-11-04  0:59           ` steph
  2014-11-05 20:14           ` sostalle
  0 siblings, 2 replies; 54+ messages in thread
From: Greg KH @ 2014-11-04  0:13 UTC (permalink / raw)
  To: steph; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 04:04:42PM -0800, steph wrote:
> On Mon, Nov 03, 2014 at 01:21:39PM -0800, Greg KH wrote:
> > On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> > > +EXPORT_SYMBOL(mausb_register_ms_driver);
> > 
> > EXPORT_SYMBOL_GPL()?  I have to ask...
> >
> The source is dual-licenced under BSD and GPL. It was our understanding
> that dual-licensed should use EXPORT_SYMBOL() instead. Is that wrong?

Talk to your company lawyers please to get confirmation of what you want
to do here, I can't answer this question, I just have to ask...

> > > +static int mausb_hcd_init(void)
> > > +{
> > > +	int ret;
> > > +
> > > +	/* register HCD driver */
> > > +	ret = platform_driver_register(&mausb_driver);
> > 
> > Why is this a platform driver?  How does this relate to platform
> > hardware?
> > 
> The driver doesn't require platform resources. It looks like a host
> controller driver but communicates over the network instead of to
> a physical host controller. There is no MA USB-specific hardware.
> 
> Should we use a struct device instead of a struct platform_device?

Yes, please make it a "virtual" device.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-04  0:13         ` Greg KH
@ 2014-11-04  0:59           ` steph
  2014-11-05 20:14           ` sostalle
  1 sibling, 0 replies; 54+ messages in thread
From: steph @ 2014-11-04  0:59 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, devel, Sean O. Stalley

On Mon, Nov 03, 2014 at 04:13:55PM -0800, Greg KH wrote:
> On Mon, Nov 03, 2014 at 04:04:42PM -0800, steph wrote:
> > On Mon, Nov 03, 2014 at 01:21:39PM -0800, Greg KH wrote:
> > > On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> > > > +EXPORT_SYMBOL(mausb_register_ms_driver);
> > > 
> > > EXPORT_SYMBOL_GPL()?  I have to ask...
> > >
> > The source is dual-licenced under BSD and GPL. It was our understanding
> > that dual-licensed should use EXPORT_SYMBOL() instead. Is that wrong?
> 
> Talk to your company lawyers please to get confirmation of what you want
> to do here, I can't answer this question, I just have to ask...
>
We have permission to go forward with the dual BSD/GPL license. I will leave
as is unless there is a future issue.
 
> > > > +static int mausb_hcd_init(void)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	/* register HCD driver */
> > > > +	ret = platform_driver_register(&mausb_driver);
> > > 
> > > Why is this a platform driver?  How does this relate to platform
> > > hardware?
> > > 
> > The driver doesn't require platform resources. It looks like a host
> > controller driver but communicates over the network instead of to
> > a physical host controller. There is no MA USB-specific hardware.
> > 
> > Should we use a struct device instead of a struct platform_device?
> 
> Yes, please make it a "virtual" device.
> 
Will do.

Thanks,
Stephanie


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-03 20:42   ` [PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
@ 2014-11-04  8:48     ` Tobias Klauser
  2014-11-04 18:02       ` Greg KH
  2014-11-12 19:36       ` Sean O. Stalley
  0 siblings, 2 replies; 54+ messages in thread
From: Tobias Klauser @ 2014-11-04  8:48 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, gregkh, devel, Sean O. Stalley

On 2014-11-03 at 21:42:52 +0100, Stephanie Wallick <stephanie.s.wallick@intel.com> wrote:
> This is where we handle media specific packets and transport. The MS driver
> interfaces with a media agnostic (MA) driver via a series of transfer pairs.
> Transfer pairs consist of a set of functions to pass MA USB packets back
> and forth between MA and MS drivers. There is one transfer pair per device
> endpoint and one transfer pair for control/management traffic. When the MA
> driver needs to send an MA USB packet, it hands the packet off to the MS
> layer where the packet is converted into an MS form and sent via TCP over
> the underlying ethernet or wireless medium. When the MS driver receives a
> packet, it converts it into an MA USB packet and hands it off the the MA
> driver for handling.
> 
> In addition, the MS driver provides an interface to inititate connection events.
> Because there are no physical MA USB ports in an MA USB host, the host must be
> notified via software when a device is connected.
> 
> Lastly, the MS driver contains a number of ioctl functions that are used by a
> utility to adjust medium-related driver parameters and connect or disconnect the
> MA USB host and device drivers.
> 
> Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
> Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
> ---
>  drivers/staging/mausb/drivers/mausb_ioctl.c      | 373 +++++++++++++++++++
>  drivers/staging/mausb/drivers/mausb_ioctl.h      |  99 +++++
>  drivers/staging/mausb/drivers/mausb_msapi.c      | 110 ++++++
>  drivers/staging/mausb/drivers/mausb_msapi.h      | 232 ++++++++++++
>  drivers/staging/mausb/drivers/mausb_tcp-device.c | 147 ++++++++
>  drivers/staging/mausb/drivers/mausb_tcp-host.c   | 144 ++++++++
>  drivers/staging/mausb/drivers/mausb_tcp.c        | 446 +++++++++++++++++++++++
>  drivers/staging/mausb/drivers/mausb_tcp.h        | 129 +++++++
>  8 files changed, 1680 insertions(+)
>  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
>  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
>  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h
> 
> diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.c b/drivers/staging/mausb/drivers/mausb_ioctl.c
> new file mode 100644
> index 0000000..0c6c6bd
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_ioctl.c

[...]

> +/**
> + * This function is used to send a message to the user, in other words, the
> + * calling process. It basically copies the message one byte at a time.
> + *
> + * @msg:	The message to be sent to the user.
> + * @buffer:	The buffer in which to put the message. This buffer was given to
> + *	    	us to fill.
> + */
> +void to_user(char *msg, long unsigned int buffer)
> +{
> +	int length = (int)strlen(msg);
> +	int bytes = 0;
> +
> +	while (length && *msg) {
> +		put_user(*(msg++), (char *)buffer++);
> +		length--;
> +		bytes++;
> +	}

Any reason not to use copy_to_user here? That way, access_ok would only
need to be executed once for the whole range.

In any case, the return value of put_user/copy_to_user will need to be
checked.

> +
> +	put_user('\0', (char *)buffer + bytes);
> +}

[...]

> +/**
> + * This function is used to read from the device file. From the perspective of
> + * the device, the user is reading information from us. This is one of the
> + * entry points to this module.
> + *
> + * @file:	The device file. We don't use it directly, but it's passed in.
> + * @buffer:	The buffer to put the message into.
> + * @length:	The max length to be read.
> + * @offset:	File offset, which we don't use but it is passed in nontheless.
> + */
> +static ssize_t mausb_read(struct file *file, char __user *buffer,
> +		size_t length, loff_t *offset)
> +{
> +	int bytes_read = 0;
> +
> +	if (*message_point == 0)
> +		return 0;
> +	while (length && *message_point) {
> +		put_user(*(message_point++), buffer++);
> +		length--;
> +		bytes_read++;
> +	}

See comment for to_user above. Why not use copy_to_user?

> +
> +	return bytes_read;
> +}
> +
> +/**
> + * This function is used to write to the device file. From the perspective of
> + * the device, the user is writing information to us. This is one of the
> + * entry points to this module.
> + *
> + * @file:	The device file. We don't use it directly, but it's passed in.
> + * @buffer:	The buffer that holds the message.
> + * @length:	The length of the message to be written.
> + * @offset:	File offset, which we don't use but it is passed in nontheless.
> + */
> +static ssize_t mausb_write(struct file *file, const char __user *buffer,
> +		size_t length, loff_t *offset)
> +{
> +	int i;
> +
> +	for (i = 0; i < length && i < BUFFER; i++)
> +		get_user(message[i], buffer + i);

copy_from_user? In any case, check the return value here as well.

> +	message_point = message;
> +
> +	return i;
> +}
> +
> +/**
> + * This function is used to execute ioctl commands, determined by ioctl_func.
> + *
> + * @file:	  The device file. We don't use it directly, but it's passed in.
> + * @ioctl_func:	  This value determines which ioctl function will be used.
> + * @ioctl_buffer: This buffer is used to transfer data to/from the device.
> + */
> +long mausb_ioctl(struct file *file, unsigned int ioctl_func,
> +		unsigned long ioctl_buffer)
> +{

This entire function needs return value checks for put_user/get_user.

> +	int bytes = 0;
> +	char *msg, *ip_addr;
> +	char chr;
> +	int ret, value;
> +	unsigned long int  long_ret;
> +
> +	switch (ioctl_func) {
> +	case IOCTL_SET_MSG:
> +		msg = (char *)ioctl_buffer;
> +		get_user(chr, msg);
> +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> +			get_user(chr, msg);
> +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> +		break;
> +	case IOCTL_GET_MSG:
> +		bytes = mausb_read(file, (char *)ioctl_buffer, 99, 0);
> +		put_user('\0', (char *)ioctl_buffer + bytes);
> +		break;
> +	case IOCTL_GET_VRSN:
> +		to_user(DRIVER_VERSION, ioctl_buffer);
> +		break;
> +	case IOCTL_GET_NAME:
> +		to_user(MAUSB_NAME, ioctl_buffer);
> +		break;
> +	case IOCTL_GADGET_C:
> +		ret = gadget_connection(1);
> +		if (ret >= 0)
> +			to_user("g_zero connect process complete", ioctl_buffer);
> +		else
> +			to_user("g_zero connect process failed", ioctl_buffer);
> +		break;
> +	case IOCTL_GADGET_D:
> +		ret = gadget_connection(0);
> +		if (ret >= 0)
> +			to_user("g_zero disconnect process complete",
> +				ioctl_buffer);
> +		else
> +			to_user("g_zero disconnect process failed",
> +				ioctl_buffer);
> +		break;
> +	case IOCTL_MED_DELAY:
> +		msg = (char *)ioctl_buffer;
> +		get_user(chr, msg);
> +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> +			get_user(chr, msg);
> +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> +		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
> +			/* TODO: handle error */
> +		}
> +		ret = set_medium_delay(value);
> +		sprintf(message_point, "DELAY VALUE: ms: %d, jiffies: %d\n",
> +			value, ret);
> +		to_user(message_point, ioctl_buffer);
> +		break;
> +	case IOCTL_SET_IP:
> +		msg = (char *)ioctl_buffer;
> +		get_user(chr, msg);
> +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> +			get_user(chr, msg);
> +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> +		ip_addr = kmalloc(strlen(message_point)+1, GFP_KERNEL);
> +		if (!ip_addr) {
> +			printk(KERN_ALERT "Memory allocation failed!\n");

No need to print an error message for memory allocation failures,
kmalloc will take care of printing a more extensive message.

> +			break;
> +		}
> +		strcpy(ip_addr, message_point);
> +		sprintf(message_point, "Connecting to ...\nIP Address: %s\n",
> +			ip_addr);
> +		to_user(message_point, ioctl_buffer);
> +		kfree(ip_addr);
> +		break;
> +	case IOCTL_SET_PORT:
> +		msg = (char *)ioctl_buffer;
> +		get_user(chr, msg);
> +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> +			get_user(chr, msg);
> +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> +		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
> +			/* TODO: handle error */
> +		}
> +		ret = set_port_no(value);
> +		sprintf(message_point, "PORT NUMBER:%d, Returned %i\n", value,
> +			ret);
> +		to_user(message_point, ioctl_buffer);
> +		break;
> +	case IOCTL_SET_IP_DECIMAL:
> +		msg = (char *)ioctl_buffer;
> +		get_user(chr, msg);
> +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> +			get_user(chr, msg);
> +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> +		if (kstrtoul((const char *)message_point, 0, &long_ret) != 0) {
> +			/* TODO: handle error */
> +		}
> +
> +		ret = set_ip_addr(long_ret);
> +		sprintf(message_point, "\nDecimal Value:%lx returned %i\n",
> +			long_ret, ret);
> +		to_user(message_point, ioctl_buffer);
> +		break;
> +	case IOCTL_SET_MAC:
> +		{
> +			u8 *mac = kmalloc(6, GFP_KERNEL);
> +			u8 *buf = (u8 __user *)ioctl_buffer;
> +			int i, ret;
> +			if (!mac) {
> +				pr_err("Memory allocation failed!\n");

See comment above. Since this is only a 6 byte buffer, it's probably
easier to just allocate it on the stack.

> +				break;
> +			}
> +			ret = copy_from_user(mac, buf, 6);
> +			if (ret) {
> +				pr_err("copy_from_user failed\n");
> +				kfree(mac);
> +				break;
> +			}
> +			for (i = 0; i < ETH_ALEN; i++)
> +				pr_info("mac[%d]=0x%x\n", i, mac[i]);
> +			ret = set_mac_addr(mac);
> +			if (ret)
> +				pr_err("unable to set MAC addr\n");
> +			kfree(mac);
> +			break;
> +		}
> +	}
> +
> +	return 0;

You probably want to return an error here in case anything went wrong
above or if the ioctl number is invalid.

> +}

[...]

> diff --git a/drivers/staging/mausb/drivers/mausb_msapi.c b/drivers/staging/mausb/drivers/mausb_msapi.c
> new file mode 100644
> index 0000000..9dd8fa5
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_msapi.c

[...]

> +/**
> + * Frees the given ms_pkt and associated buffers. This function is not
> + * necessary to use the API, but could be useful on both sides of the interface.
> + */
> +void mausb_free_ms_pkt(struct ms_pkt *pkt)
> +{
> +	int i;
> +	void *current_buf;
> +
> +	for (i = 0; i < pkt->nents; ++i) {
> +		current_buf = pkt[i].kvec->iov_base;
> +		if (NULL != current_buf) {
> +			kfree(current_buf);
> +		} else {
> +			printk(KERN_DEBUG "%s: cannot find buffer for "
> +				"kvec #%i in ms_pkt at %p\n",
> +				__func__, i, pkt->kvec);

pr_debug()

> +		}
> +	}
> +
> +	kfree(pkt);
> +
> +	return;
> +}
> +EXPORT_SYMBOL(mausb_free_ms_pkt);
> +
> +/**
> + * Calculates the total length of the data in a ms_pkt. Returns the total
> + * length of the data in the ms_pkt, or a negative errno.
> + */
> +int mausb_ms_pkt_length(struct ms_pkt *pkt)
> +{
> +	int i;
> +	int total_length = 0;
> +
> +	for (i = 0; i < pkt->nents; ++i)
> +		total_length += pkt[i].kvec->iov_len;
> +
> +	printk(KERN_DEBUG "%s: total *kvec length: %i\n", __func__,
> +		total_length);

pr_debug()

> +
> +	return total_length;
> +}

[...]

> diff --git a/drivers/staging/mausb/drivers/mausb_tcp-device.c b/drivers/staging/mausb/drivers/mausb_tcp-device.c
> new file mode 100644
> index 0000000..28978a0
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_tcp-device.c

[...]

> +static int mausb_tcp_device_connect(int on)
> +{
> +	int ret;
> +
> +	if (on && dev_tcp_medium->socket == NULL) {
> +		ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
> +			&dev_tcp_medium->socket);
> +
> +		if (0 > ret) /* TODO: real errorchecking */
> +			return ret;
> +
> +		do {
> +			ret = kernel_connect(dev_tcp_medium->socket,
> +				&dev_tcp_medium->addr,
> +				sizeof(dev_tcp_medium->addr_in), O_RDWR);
> +			printk(KERN_DEBUG "%s:kernel_connect returned %i\n",
> +				__func__, ret);

pr_debug(), here any in several other places across the file...

> +
> +			if (0 > ret) {
> +				/* poll until we can connect sucessfully */
> +				msleep(MAUSB_TCP_DEV_CONNECT_POLL_MS);
> +			}
> +
> +
> +		} while (0 > ret);
> +
> +		/*spawn off a listening thread */
> +		dev_tcp_medium->recv_task = kthread_run(mausb_tcp_device_thread,
> +			NULL, "mausb_tcp_device_thread");

kthread_run might return an ERR_PTR which needs to be handled here.

> +	}
> +
> +	ret = dev_tcp_medium->ma_driver->device_connect(on);
> +
> +	return ret;
> +}

[...]

> diff --git a/drivers/staging/mausb/drivers/mausb_tcp-host.c b/drivers/staging/mausb/drivers/mausb_tcp-host.c
> new file mode 100644
> index 0000000..0302031
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_tcp-host.c

[...]

> +static int mausb_tcp_host_connect(int on)
> +{
> +	int ret;
> +
> +	if (on) {
> +		ret = kernel_bind(host_tcp_medium->setup_socket,
> +			&host_tcp_medium->addr,
> +			sizeof(host_tcp_medium->addr_in));

Missing error handling.

> +
> +		ret = kernel_listen(host_tcp_medium->setup_socket,
> +			MAUSB_TCP_MAX_NUM_CHANNELS);

Missing error handling.

> +		printk(KERN_DEBUG "%s: kernel_listen returned %i\n",
> +			__func__, ret);
> +
> +		ret = kernel_accept(host_tcp_medium->setup_socket,
> +				    &host_tcp_medium->socket, 0);
> +		printk(KERN_DEBUG "%s:kernel_accept returned %i\n",
> +			__func__, ret);
> +
> +		if (0 > ret)
> +			return ret;

kernel_accept might return negative values in case of an error, which
needs to be handled properly here.

> +
> +		if (NULL == host_tcp_medium->recv_task) {
> +			host_tcp_medium->recv_task = kthread_run(
> +				mausb_tcp_host_thread, NULL,
> +				"mausb_tcp_host_thread");
> +		}
> +	}
> +
> +	ret = host_tcp_medium->ma_driver->device_connect(on);
> +
> +	return ret;
> +}

[...]

> diff --git a/drivers/staging/mausb/drivers/mausb_tcp.c b/drivers/staging/mausb/drivers/mausb_tcp.c
> new file mode 100644
> index 0000000..291139e
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_tcp.c

[...]

> +int mausb_tcp_receive_loop(struct mausb_tcp_medium *tcp_medium)
> +{
> +	struct msghdr msg;
> +	struct ms_pkt *pkt;
> +	int data_rcvd = 0;
> +
> +	mausb_tcp_init_msg(&msg);
> +
> +	while (!kthread_should_stop()) {
> +
> +		pkt = kzalloc(sizeof(struct ms_pkt), GFP_KERNEL);

Missing return value check.

> +
> +		printk(KERN_DEBUG "%s: preparing to receive data\n",
> +			__func__);
> +
> +		data_rcvd = mausb_tcp_receive_packet(tcp_medium, &msg, pkt);
> +
> +		if (0 >= data_rcvd) {
> +			printk(KERN_DEBUG "%s: received no data (err %i)\n",
> +				__func__, data_rcvd);
> +
> +			sock_release(tcp_medium->socket);
> +			return data_rcvd;
> +
> +		} else {
> +			printk(KERN_DEBUG "%s: received %i bytes\n",
> +				__func__, data_rcvd);
> +		}
> +
> +		if (data_rcvd > 0) {
> +			mausb_transfer_packet(pkt,
> +				&tcp_medium->ma_driver->pkt_dmux);
> +		}
> +
> +		data_rcvd = 0;
> +	}
> +
> +	sock_release(tcp_medium->socket);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(mausb_tcp_receive_loop);

[...]

> +/**
> + * initialization function
> + */
> +struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
> +	enum mausb_tcp_module_type type)
> +{
> +	struct mausb_tcp_medium *medium;
> +	int ret;
> +
> +	printk(KERN_DEBUG "%s\n", __func__);
> +
> +	medium = kzalloc(sizeof(struct mausb_tcp_medium), GFP_KERNEL);
> +	if (NULL == medium) {
> +		printk(KERN_DEBUG "%s: memory allocation failed\n", __func__);

No error message needed, kmalloc will take care of it.

> +		return NULL;
> +	}
> +
> +	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
> +		&medium->setup_socket);

Error handling is missing.

> +
> +	medium->addr_in.sin_family = AF_INET;
> +	medium->addr_in.sin_port = htons(MAUSB_TCP_PORT_HOST);
> +
> +	spin_lock_init(&medium->lock);
> +
> +	tcp_medium[type] = medium;
> +
> +	return medium;
> +}
> +EXPORT_SYMBOL(alloc_init_mausb_tcp_medium);

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 00/10] MA USB drivers cover letter
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
                     ` (9 preceding siblings ...)
  2014-11-03 20:42   ` [PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
@ 2014-11-04  9:00   ` Bjørn Mork
  2014-11-05  1:31     ` sostalle
  10 siblings, 1 reply; 54+ messages in thread
From: Bjørn Mork @ 2014-11-04  9:00 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, gregkh, devel, linux-usb

[added linux-usb@vger.kernel.org Cc]

Stephanie Wallick <stephanie.s.wallick@intel.com> writes:

> Media Agnostic (MA) USB enables the USB protocol to be used over a wide
> range of physical media. MA USB is a relatively new protocol and is
> currently unsupported in the Linux kernel. This patch set adds the
> following drivers with the following capabilities:
>
> 1) MA USB Host:
>         - provides functionality of a USB Host Controller.
>         - implements MA USB protocol for a MA USB host.
>         - provides MA USB packet transport over TCP
>
> 2) MA USB Device:
>         - provides functionality of a USB Device Controller.
>         - implements MA USB protocol for a MA USB device.
>         - provides MA USB packet transport over TCP

Nice.  But don't you think this deserves the attention of the linux-usb
mailing list?  Yes, Greg's attention is of course good to have too :-)
But  I believe this is of interest to more people, who might not read
everything on linux-kernel.

Has there been any thought/discussion about the relationship to the
existing usbip drivers, which just moved out of staging? Is a usbip
userspace compatibility layer feasible sometime in the future?


Bjørn

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-04  8:48     ` Tobias Klauser
@ 2014-11-04 18:02       ` Greg KH
  2014-11-12 19:36       ` Sean O. Stalley
  1 sibling, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-04 18:02 UTC (permalink / raw)
  To: Tobias Klauser; +Cc: Stephanie Wallick, devel, linux-kernel, Sean O. Stalley

On Tue, Nov 04, 2014 at 09:48:33AM +0100, Tobias Klauser wrote:
> On 2014-11-03 at 21:42:52 +0100, Stephanie Wallick <stephanie.s.wallick@intel.com> wrote:
> > This is where we handle media specific packets and transport. The MS driver
> > interfaces with a media agnostic (MA) driver via a series of transfer pairs.
> > Transfer pairs consist of a set of functions to pass MA USB packets back
> > and forth between MA and MS drivers. There is one transfer pair per device
> > endpoint and one transfer pair for control/management traffic. When the MA
> > driver needs to send an MA USB packet, it hands the packet off to the MS
> > layer where the packet is converted into an MS form and sent via TCP over
> > the underlying ethernet or wireless medium. When the MS driver receives a
> > packet, it converts it into an MA USB packet and hands it off the the MA
> > driver for handling.
> > 
> > In addition, the MS driver provides an interface to inititate connection events.
> > Because there are no physical MA USB ports in an MA USB host, the host must be
> > notified via software when a device is connected.
> > 
> > Lastly, the MS driver contains a number of ioctl functions that are used by a
> > utility to adjust medium-related driver parameters and connect or disconnect the
> > MA USB host and device drivers.
> > 
> > Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
> > Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
> > ---
> >  drivers/staging/mausb/drivers/mausb_ioctl.c      | 373 +++++++++++++++++++
> >  drivers/staging/mausb/drivers/mausb_ioctl.h      |  99 +++++
> >  drivers/staging/mausb/drivers/mausb_msapi.c      | 110 ++++++
> >  drivers/staging/mausb/drivers/mausb_msapi.h      | 232 ++++++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp-device.c | 147 ++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp-host.c   | 144 ++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp.c        | 446 +++++++++++++++++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp.h        | 129 +++++++
> >  8 files changed, 1680 insertions(+)
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h
> > 
> > diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.c b/drivers/staging/mausb/drivers/mausb_ioctl.c
> > new file mode 100644
> > index 0000000..0c6c6bd
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_ioctl.c
> 
> [...]
> 
> > +/**
> > + * This function is used to send a message to the user, in other words, the
> > + * calling process. It basically copies the message one byte at a time.
> > + *
> > + * @msg:	The message to be sent to the user.
> > + * @buffer:	The buffer in which to put the message. This buffer was given to
> > + *	    	us to fill.
> > + */
> > +void to_user(char *msg, long unsigned int buffer)
> > +{
> > +	int length = (int)strlen(msg);
> > +	int bytes = 0;
> > +
> > +	while (length && *msg) {
> > +		put_user(*(msg++), (char *)buffer++);
> > +		length--;
> > +		bytes++;
> > +	}
> 
> Any reason not to use copy_to_user here? That way, access_ok would only
> need to be executed once for the whole range.
> 
> In any case, the return value of put_user/copy_to_user will need to be
> checked.

Never use put_user if you can help it, this whole function should go
away, and copy_to_user() should be used at the caller sites instead as
you point out.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 10/10] added kernel build, configuration, and TODO files
       [not found]       ` <54591319.c3b5440a.7374.5f85SMTPIN_ADDED_BROKEN@mx.google.com>
@ 2014-11-04 18:02         ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-04 18:02 UTC (permalink / raw)
  To: sostalle; +Cc: Stephanie Wallick, linux-kernel, devel

On Tue, Nov 04, 2014 at 09:55:19AM -0800, sostalle wrote:
> >On Mon, Nov 03, 2014 at 01:24:04PM -0800, Greg KH wrote:
> >>On Mon, Nov 03, 2014 at 12:42:57PM -0800, Stephanie Wallick wrote:
> >> --- /dev/null
> >> +++ b/drivers/staging/mausb/TODO
> >> @@ -0,0 +1,14 @@
> >> +TODO:
> >> +	- checkpatch.pl cleanups
> >
> >Is this still true?
> >
> 
> checkpatch.pl reports:
> total: 7 errors, 208 warnings, 10489 lines checked

Ok, fair enough.

> >And why does this need to be a staging driver?  What's wrong with making
> >it a "real" driver now?
> >
> 
> The short answer is: We don't think it's ready to be "real".
> 
> We didn't want to release it as a "real" driver because:
> 	- It's not stable enough yet.
> 	- It doesn't implement all the features required by the MA USB spec.
> 	- The MA USB spec isn't standalone. It requires a supplemental spec
> 	  to define media-specific behavior, like how MA USB packets are
> 	  encapsulated, how to discover MA USB devices on a network, etc.
> 	  So far, no media-specific specifications have been published.
> 	- There are no commercially-available Media Agnostic USB devices.
> 
> We wanted to release it to staging now because:
> 	- We have received requests from multiple companies for our host MA USB
> 	  driver. Putting it in staging seemed the best way to distribute it.
> 	- We feel that releasing what we have to staging now could promote
> 	  collaboration on one driver & help prevent duplicate work.

Ok, please include that information in the first email, it's much more
helpful :)

Can you resend this series, and cc: the linux-usb mailing list, and
address the "what about usbip?" questions as well?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 00/10] MA USB drivers cover letter
  2014-11-04  9:00   ` [PATCH 00/10] MA USB drivers cover letter Bjørn Mork
@ 2014-11-05  1:31     ` sostalle
  0 siblings, 0 replies; 54+ messages in thread
From: sostalle @ 2014-11-05  1:31 UTC (permalink / raw)
  To: Bjørn Mork; +Cc: Stephanie Wallick, linux-kernel, gregkh, devel, linux-usb

[with a valid Message-ID]

On Tue, Nov 04, 2014 at 10:00:32AM +0100, Bjørn Mork wrote:
> [added linux-usb@vger.kernel.org Cc]
> 
> Stephanie Wallick <stephanie.s.wallick@intel.com> writes:
> 
> > Media Agnostic (MA) USB enables the USB protocol to be used over a wide
> > range of physical media. MA USB is a relatively new protocol and is
> > currently unsupported in the Linux kernel. This patch set adds the
> > following drivers with the following capabilities:
> >
> > 1) MA USB Host:
> >         - provides functionality of a USB Host Controller.
> >         - implements MA USB protocol for a MA USB host.
> >         - provides MA USB packet transport over TCP
> >
> > 2) MA USB Device:
> >         - provides functionality of a USB Device Controller.
> >         - implements MA USB protocol for a MA USB device.
> >         - provides MA USB packet transport over TCP
> 
> Nice.  But don't you think this deserves the attention of the linux-usb
> mailing list?  Yes, Greg's attention is of course good to have too :-)
> But  I believe this is of interest to more people, who might not read
> everything on linux-kernel.


This is probably more relevant/interesting to the people on linux-usb.
Since we were trying to get this driver into staging, we thought linux-kernel
was the right place to send the patches. We can send the next set out to
linux-usb as well.


> Has there been any thought/discussion about the relationship to the
> existing usbip drivers, which just moved out of staging? Is a usbip
> userspace compatibility layer feasible sometime in the future?

 
That discussion hasn't happened. usbip has a different protocol than MA USB,
so much of the code cannot be reused.

I just briefly looked into the userspace code for usbip. It looks like the
userspace compatibility layer is just a utility for establishing the TCP
connection between the host and device & choosing what devices to connect,
correct? We have a similar utility (see patch 9/10) which could probably
be replaced by the usbip userspace utilities.

Thanks,
Sean

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-04  0:13         ` Greg KH
  2014-11-04  0:59           ` steph
@ 2014-11-05 20:14           ` sostalle
  2014-11-05 22:08             ` Greg KH
  1 sibling, 1 reply; 54+ messages in thread
From: sostalle @ 2014-11-05 20:14 UTC (permalink / raw)
  To: Greg KH; +Cc: steph, linux-kernel, devel

On Mon, Nov 03, 2014 at 04:13:55PM -0800, Greg KH wrote:
> On Mon, Nov 03, 2014 at 04:04:42PM -0800, steph wrote:
> > On Mon, Nov 03, 2014 at 01:21:39PM -0800, Greg KH wrote:
> > > On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
[snip] 
> > > > +static int mausb_hcd_init(void)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	/* register HCD driver */
> > > > +	ret = platform_driver_register(&mausb_driver);
> > > 
> > > Why is this a platform driver?  How does this relate to platform
> > > hardware?
> > > 
> > The driver doesn't require platform resources. It looks like a host
> > controller driver but communicates over the network instead of to
> > a physical host controller. There is no MA USB-specific hardware.
> > 
> > Should we use a struct device instead of a struct platform_device?
> 
> Yes, please make it a "virtual" device.
> 

Is it OK for our virtual host controller to use struct platform_device?

The other virtual host controllers (usbip/vhci_hcd.c & gadget/udc/dummy_hcd.c)
use the platform_device struct. Unless I am missing something, it doesn't look
like the other virtual host controllers use platform resources.

If it is not ok, is there a good example somewhere of a virtual non-platform
device?

Thank You,
Sean O. Stalley

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-05 20:14           ` sostalle
@ 2014-11-05 22:08             ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-05 22:08 UTC (permalink / raw)
  To: sostalle; +Cc: steph, linux-kernel, devel

On Wed, Nov 05, 2014 at 12:14:33PM -0800, sostalle wrote:
> On Mon, Nov 03, 2014 at 04:13:55PM -0800, Greg KH wrote:
> > On Mon, Nov 03, 2014 at 04:04:42PM -0800, steph wrote:
> > > On Mon, Nov 03, 2014 at 01:21:39PM -0800, Greg KH wrote:
> > > > On Mon, Nov 03, 2014 at 12:42:48PM -0800, Stephanie Wallick wrote:
> [snip] 
> > > > > +static int mausb_hcd_init(void)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	/* register HCD driver */
> > > > > +	ret = platform_driver_register(&mausb_driver);
> > > > 
> > > > Why is this a platform driver?  How does this relate to platform
> > > > hardware?
> > > > 
> > > The driver doesn't require platform resources. It looks like a host
> > > controller driver but communicates over the network instead of to
> > > a physical host controller. There is no MA USB-specific hardware.
> > > 
> > > Should we use a struct device instead of a struct platform_device?
> > 
> > Yes, please make it a "virtual" device.
> > 
> 
> Is it OK for our virtual host controller to use struct platform_device?
> 
> The other virtual host controllers (usbip/vhci_hcd.c & gadget/udc/dummy_hcd.c)
> use the platform_device struct. Unless I am missing something, it doesn't look
> like the other virtual host controllers use platform resources.
> 
> If it is not ok, is there a good example somewhere of a virtual non-platform
> device?

If your device is not really a platform device (i.e. no platform
resources), then just create a virtual device with a call to
device_create() and don't pass in a parent pointer.  But you need to
create a class for it, which is a pain, but shouldn't be that hard.

Hope this helps,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
       [not found] <MA USB drivers>
  2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
@ 2014-11-11  2:09 ` Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
                     ` (10 more replies)
  1 sibling, 11 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we interface with the existing USB stack and implement the
functionality of a USB host controller driver. From the host's perspective,
we appear as just another USB host controller. However, instead of passing
traffic along a wired USB bus, the driver hands USB packets off for transport
per Media Agnostic USB protocol.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_hcd.c | 981 ++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_hcd.h | 184 ++++++
 2 files changed, 1165 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_hcd.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hcd.h

diff --git a/drivers/staging/mausb/drivers/mausb_hcd.c b/drivers/staging/mausb/drivers/mausb_hcd.c
new file mode 100755
index 0000000..b35a62b
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hcd.c
@@ -0,0 +1,981 @@
+/* Name:	mausb_hcd.c
+ * Description: Creates and initializes a virtual USB host controller driver
+ *	        for the Media Agnostic USB host driver.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/gadget.h>
+#include <linux/kthread.h>
+#include <linux/random.h>
+
+#include "mausb_hcd.h"
+#include "mausb_hub.h"
+#include "mausb_pkt.h"
+#include "mausb_mem-host.h"
+#include "mausb_msapi.h"
+#include "mausb_mgmt.h"
+#include "mausb_state.h"
+#include "mausb_tx.h"
+
+static int mausb_bus_match(struct device *dev, struct device_driver *drv)
+{
+	if (strncmp(dev->bus->name, drv->name, strlen(drv->name)))
+		return 0;	/* no match */
+	else
+		return 1;	/* match */
+}
+
+static int mausb_bus_probe(struct device *dev)
+{
+	return mausb_probe(dev);
+}
+
+static int mausb_bus_remove(struct device *dev)
+{
+	return mausb_remove(dev);
+}
+
+static void mausb_dev_release(struct device *dev)
+{
+	/* TODO: if we dynamically allocate anything, free it here */
+}
+
+static struct class	*mausb_class;
+
+static struct bus_type mausb_bus_type = {
+	.name		= MAUSB_NAME,
+	.match		= mausb_bus_match,
+	.probe		= mausb_bus_probe,
+	.remove		= mausb_bus_remove,
+};
+
+static struct device_driver mhcd_driver = {
+	.name		= MAUSB_NAME,
+	.bus		= &mausb_bus_type,
+	.owner		= THIS_MODULE,
+};
+
+static struct mausb_hcd mhcd;
+
+struct api_context {
+	struct completion	done;
+	int			status;
+};
+
+/*
+ * pointer conversion functions
+ */
+inline struct mausb_hcd *usb_hcd_to_mausb_hcd(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd))
+		return *((struct mausb_hcd **) (hcd->hcd_priv));
+	else
+		return *((struct mausb_hcd **) (hcd->primary_hcd->hcd_priv));
+}
+
+inline struct usb_hcd *mausb_hcd_to_usb_hcd(struct mausb_hcd *mhcd)
+{
+	if (mhcd->shared_hcd && !usb_hcd_is_primary_hcd(mhcd->shared_hcd))
+		return mhcd->shared_hcd;
+	else
+		return mhcd->usb_hcd;
+}
+
+inline struct device *mausb_hcd_to_dev(struct mausb_hcd *mhcd)
+{
+	return mausb_hcd_to_usb_hcd(mhcd)->self.controller;
+}
+
+inline struct mausb_urb *usb_urb_to_mausb_urb(struct urb *urb)
+{
+	return (struct mausb_urb *) urb->hcpriv;
+}
+/* ----------------------------------------------------------------- */
+
+/**
+ * @maurb:	Media agnostic structure with URB to release.
+ * @status:	Status for URB that is getting released.
+ *
+ * Removes an URB from the queue, deletes the media agnostic information in
+ * the urb, and gives the URB back to the HCD. Caller must be holding the
+ * driver's spinlock.
+ */
+void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status)
+{
+	struct urb		*urb;
+	struct usb_hcd		*hcd;
+	struct api_context	*ctx = NULL;
+	unsigned long		irq_flags;
+
+	hcd = mausb_hcd_to_usb_hcd(&mhcd);
+
+	spin_lock_irqsave(&mhcd.giveback_lock, irq_flags);
+
+	if (!maurb) {
+		mausb_err(&mhcd, "%s: no maurb\n", __func__);
+		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
+		return;
+	} else {
+		urb = maurb->urb;
+		ctx = urb->context;
+	}
+
+	if (!urb) {
+		mausb_err(&mhcd, "%s: no urb\n", __func__);
+		mausb_internal_drop_maurb(maurb, &mhcd);
+		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
+		return;
+	}
+
+	mausb_dbg(&mhcd, "%s: returning urb with status %i\n", __func__, status);
+
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
+
+	/* remove the mausb-specific data */
+	mausb_internal_drop_maurb(maurb, &mhcd);
+
+	spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
+}
+
+/**
+ * Adds an URB to the endpoint queue then calls the URB handler. URB is wrapped
+ * in media agnostic structure before being enqueued.
+ */
+static int mausb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t memflags)
+{
+	int			ret = 0;
+	struct mausb_urb	*maurb;
+	struct mausb_host_ep	*ep;
+	unsigned long		irq_flags;
+
+	if (!hcd || !urb) {
+		pr_err("%s: no %s\n", __func__, (hcd ? "urb" : "USB hcd"));
+	}
+
+	ep   = usb_to_ma_endpoint(urb->ep);
+
+	if (!ep) {
+		mausb_err(&mhcd, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		mausb_err(&mhcd, "%s: urb already unlinked, status is %i\n",
+			__func__, urb->status);
+		return urb->status;
+	}
+
+	/* If the endpoint isn't activated, we can't enqueue anything. */
+	if (MAUSB_EP_HANDLE_UNASSIGNED == ep->ep_handle_state) {
+		mausb_err(&mhcd, "%s: endpoint handle unassigned\n", __func__);
+		return -EPIPE;
+	}
+
+	if (USB_SPEED_FULL != urb->dev->speed) /* suppress checks */
+		ep->max_pkt = usb_endpoint_maxp(&urb->ep->desc);
+
+	/* initialize the maurb */
+	maurb = mausb_alloc_maurb(ep, memflags);
+	if (!maurb) {
+		mausb_err(&mhcd, "could not allocate memory for MA USB urb\n");
+		return -ENOMEM;
+	}
+
+	/* set maurb member values */
+	maurb->urb = urb;
+	urb->hcpriv = maurb;
+
+	/* submit urb to hcd and add to endpoint queue */
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret < 0) {
+		mausb_err(&mhcd, "urb enqueue failed: error %d\n", ret);
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+		return ret;
+	}
+
+	/* get usb device and increment reference counter */
+	if (!mhcd.udev) {
+		mhcd.udev = urb->dev;
+		usb_get_dev(mhcd.udev);
+	}
+
+	/* add urb to queue list */
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	list_add_tail(&maurb->urb_list, &ep->urb_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	/* add urb to ma hcd urb list */
+	spin_lock_irqsave(&mhcd.urb_list_lock, irq_flags);
+	list_add_tail(&maurb->ma_hcd_urb_list, &mhcd.enqueue_urb_list);
+	spin_unlock_irqrestore(&mhcd.urb_list_lock, irq_flags);
+
+	/* send to MA transfer process */
+	wake_up(&mhcd.waitq);
+
+	return ret;
+}
+
+/**
+ * Dequeues an URB.
+ */
+static int mausb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	int			ret	= 0;
+	struct mausb_host_ep	*ep = usb_to_ma_endpoint(urb->ep);
+	struct mausb_urb	*maurb = usb_urb_to_mausb_urb(urb);
+	unsigned long		irq_flags;
+
+	/* For debugging - we want to know who initiated URB dequeue. */
+	dump_stack();
+
+	if (ep->active_transfer == maurb) {
+		ret = mausb_tx_dev_mgmt_req_ep(CancelTransferReq,
+			&mhcd.ma_dev.mgmt, maurb->dev, true, ep);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		ep->active_transfer = NULL;
+		ep->state.tx_pending = 0;
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	}
+
+	/*
+	 * Make sure urb hasn't been unlinked or already completed.
+	 * Dequeue must fail if usb_hcd_check_unlink_urb() fails.
+	 */
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+
+	if (ret < 0) {
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		mausb_err(&mhcd, "%s: urb already unlinked or completed, %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	/* check to make sure our urb queue is not empty */
+	if (list_empty(&ep->urb_list)) {
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		mausb_err(&mhcd, "%s: urb queue is empty\n", __func__);
+		return -ENXIO;
+	}
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	/* now we can give back URB */
+	spin_lock_irqsave(&mhcd.hcd_lock, irq_flags);
+	mausb_unlink_giveback_urb(maurb, -EINPROGRESS);
+	spin_unlock_irqrestore(&mhcd.hcd_lock, irq_flags);
+
+	return ret;
+}
+
+/**
+ * Called by usb core to suspend the bus. Once suspended, hcd waits in
+ * that state until it is resumed by mausb_bus_resume().
+ *
+ * Note: sections are commented out to accomidate devices that don't yet
+ * support SleepReq packets.
+ *
+ * Always returns zero.
+ */
+static int mausb_bus_suspend(struct usb_hcd *hcd)
+{
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	/* stop polling */
+	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+
+	/*
+	 * Avoid suspend/resume race condition by making sure there aren't any
+	 * devices in the middle of resuming. If a connected device is
+	 * resuming, suspend should fail.
+	 */
+	if (mhcd.resuming) {
+		mausb_err(&mhcd, "%s: suspend failed, device is resuming\n",
+			 __func__);
+		return -EBUSY;
+	}
+
+	mausb_dbg(&mhcd, "%s: suspending mausb driver\n", __func__);
+
+	roothub->rh_state = MAUSB_RH_SUSPEND;
+	hcd->state = HC_STATE_SUSPENDED;
+
+	return 0;
+}
+
+/**
+ * Called by usb core to resume hcd after bus suspension.
+ *
+ * Returns 0 if resume was successful, otherwise returns negative error
+ * value.
+ */
+static int mausb_bus_resume(struct usb_hcd *hcd)
+{
+	int ret = 0;
+	struct mausb_dev *top_dev = mhcd.ma_dev.top_dev;
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		mausb_err(&mhcd, "%s: hcd not fully powered\n", __func__);
+		return -ESHUTDOWN;
+	}
+
+	mausb_dbg(&mhcd, "%s: resuming mausb driver\n", __func__);
+
+	hcd->state = HC_STATE_RUNNING;
+	roothub->rh_state = MAUSB_RH_RUNNING;
+
+	if (NULL != top_dev) {
+		ret = mausb_tx_dev_mgmt_req(WakeReq, &mhcd.ma_dev.mgmt,
+			top_dev, true);
+
+		if (ret < 0) {
+			mausb_err(&mhcd, "%s: WakeReq was unsuccessful"
+				" (error %i)\n", __func__, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Returns the hardware-chosen device address.
+ */
+static int mausb_address_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	int			ret = 0;
+	struct ma_dev		*ma_dev;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_host_ep	*ma_ep;
+
+	ma_dev = &mhcd.ma_dev;
+	if (NULL == ma_dev)
+		return -EINVAL;
+
+	mausb_dev = mausb_find_dev_host(ma_dev, udev);
+	if (NULL == mausb_dev)
+		return -ENODEV;
+
+	ret = mausb_tx_dev_mgmt_req(USBDevHandleReq, &ma_dev->mgmt,
+		mausb_dev, true);
+
+	if (-ETIMEDOUT == ret) {
+		mausb_err(&mhcd, "USBDevHandleReq timed out\n");
+	} else if (0 > ret) {
+		mausb_err(&mhcd, "USBDevHandleReq failed with error %i\n", ret);
+	} else {
+		ret = mausb_tx_dev_mgmt_req(EPHandleReq, &ma_dev->mgmt,
+			mausb_dev, true);
+
+		if (-ETIMEDOUT == ret) {
+			mausb_err(&mhcd, "EPHandleReq timed out\n");
+		} else if (0 > ret) {
+			mausb_err(&mhcd, "EPHandleReq failed with error %i\n",
+					ret);
+		} else {
+			ret = mausb_tx_dev_mgmt_req(SetUSBDevAddrReq,
+				&ma_dev->mgmt, mausb_dev, true);
+
+			if (-ETIMEDOUT == ret) {
+				mausb_err(&mhcd, "SetUSBDevAddrReq timed out\n");
+			} else if (0 > ret) {
+				mausb_err(&mhcd, "SetUSBDevAddrReq failed with"
+					" error %i\n", ret);
+			} else {
+				ma_ep = mausb_find_ep_host(&udev->ep0,
+					mausb_dev);
+				ret = mausb_tx_dev_mgmt_req_ep(ModifyEP0Req,
+					&ma_dev->mgmt, mausb_dev, true, ma_ep);
+			}
+		}
+	}
+
+	/* TODO: handle failed enumeration */
+
+	return 0;
+}
+
+/**
+ * Resets everything to default values. Always returns zero.
+ */
+static int mausb_reset(struct usb_hcd *hcd)
+{
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	mausb_dbg(&mhcd, "%s: resetting MA USB host driver . . .\n", __func__);
+
+	roothub->rh_state = MAUSB_RH_RESETTING;
+
+	if (mausb_is_ss_hcd(hcd)) {
+		hcd->speed = HCD_USB3;
+		hcd->self.root_hub->speed = USB_SPEED_SUPER;
+	} else {
+		hcd->speed = HCD_USB2;
+		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+		hcd->has_tt = 1;
+	}
+
+	hcd->uses_new_polling = 1;
+	hcd->self.sg_tablesize = 0;
+
+	mausb_init_port_status(&mhcd.root_hub);
+	mausb_init_port_status(&mhcd.shared_root_hub);
+
+	return 0;
+}
+
+int mausb_hcd_thread(void *data)
+{
+	struct mausb_hcd *mhcd = (struct mausb_hcd *)data;
+	struct mausb_urb *ma_urb, *next_ma_urb;
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	while (!kthread_should_stop()) {
+		spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+		list_for_each_entry_safe(ma_urb, next_ma_urb,
+			&mhcd->enqueue_urb_list, ma_hcd_urb_list) {
+
+			list_move(&ma_urb->ma_hcd_urb_list,
+				&mhcd->transfer_urb_list);
+
+			spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+			ma_ep = ma_urb->ep;
+			start_ma_transfer(ma_ep, ma_urb,
+				usb_pipein(ma_urb->urb->pipe));
+
+			spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+		}
+		spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+		wait_event_interruptible(mhcd->waitq,
+			!list_empty(&mhcd->enqueue_urb_list) ||
+			kthread_should_stop());
+	}
+
+	do_exit(0);
+	return 0;
+}
+
+/**
+ * Tells the hcd to start running. Always returns zero.
+ */
+static int mausb_start(struct usb_hcd *hcd)
+{
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	mausb_dbg(&mhcd, "%s: starting MA USB driver . . .\n", __func__);
+
+	hcd->state = HC_STATE_RUNNING;
+	roothub->rh_state = MAUSB_RH_RUNNING;
+
+	spin_lock_init(&mhcd.hcd_lock);
+	INIT_LIST_HEAD(&mhcd.ma_dev.dev_list);
+	INIT_LIST_HEAD(&mhcd.enqueue_urb_list);
+	spin_lock_init(&mhcd.urb_list_lock);
+	INIT_LIST_HEAD(&mhcd.transfer_urb_list);
+	spin_lock_init(&mhcd.giveback_lock);
+	init_waitqueue_head(&mhcd.waitq);
+	mhcd.ma_hcd_task_data = (void *)&mhcd;
+	mhcd.ma_hcd_task = kthread_run(mausb_hcd_thread,
+		mhcd.ma_hcd_task_data, "mausb_hcd_thread");
+
+	return 0;
+}
+
+/**
+ * Called when driver is removed (specifically during usb_remove_hcd). This is
+ * where we tell the hcd to stop writing memory and doing I/O.
+ */
+static void mausb_stop(struct usb_hcd *hcd)
+{
+	if (mhcd.ma_hcd_task != NULL) {
+		kthread_stop(mhcd.ma_hcd_task);
+		mhcd.ma_hcd_task = NULL;
+	}
+
+	mausb_dbg(&mhcd, "%s: stopping mausb driver . . .\n", __func__);
+}
+
+static const struct hc_driver mausb_hc_driver = {
+	.description = "mausb hcd",
+	.product_desc = "mausb host controller",
+	.hcd_priv_size = sizeof(struct mausb_hcd),
+	.irq = NULL,
+	.flags = HCD_USB3,
+	.reset = &mausb_reset,
+	.start = &mausb_start,
+	.stop = &mausb_stop,
+	.urb_enqueue = &mausb_urb_enqueue,
+	.urb_dequeue = &mausb_urb_dequeue,
+	.hub_status_data = &mausb_hub_status_data,
+	.hub_control = &mausb_hub_control,
+	.bus_suspend = &mausb_bus_suspend,
+	.bus_resume = &mausb_bus_resume,
+	.alloc_dev = &mausb_alloc_dev,
+	.free_dev =  &mausb_free_dev,
+	.add_endpoint =    &mausb_add_endpoint,
+	.drop_endpoint =   &mausb_drop_endpoint,
+	.check_bandwidth = &mausb_check_bandwidth,
+	.reset_bandwidth = &mausb_reset_bandwidth,
+	.address_device =  &mausb_address_device,
+};
+
+/**
+ * Sets the host_bos fields to the proper initial values per USB3 spec,
+ * section 10.13.1.
+ */
+static int mausb_set_host_bos(struct mausb_host_bos *host_bos)
+{
+	/* BOS Descriptor */
+	host_bos->bos_des.bLength         = USB_DT_BOS_SIZE;
+	host_bos->bos_des.bDescriptorType = USB_DT_BOS;
+	host_bos->bos_des.wTotalLength    = sizeof(struct mausb_host_bos);
+	host_bos->bos_des.bNumDeviceCaps  = MAUSB_HOST_NUM_DEV_CAPS;
+
+	/* SuperSpeed USB Device Capability */
+	host_bos->ss_cap_des.bLength               = USB_DT_USB_SS_CAP_SIZE;
+	host_bos->ss_cap_des.bDescriptorType       = USB_DT_DEVICE_CAPABILITY;
+	host_bos->ss_cap_des.bDevCapabilityType    = USB_SS_CAP_TYPE;
+	host_bos->ss_cap_des.bmAttributes          = USB_LTM_SUPPORT;
+	host_bos->ss_cap_des.wSpeedSupported       = USB_5GBPS_OPERATION;
+	host_bos->ss_cap_des.bFunctionalitySupport = MAUSB_SUPER_SPEED;
+	host_bos->ss_cap_des.bU1devExitLat         = MAUSB_HOST_U1_DEV_EXIT_LAT;
+	host_bos->ss_cap_des.bU2DevExitLat         = MAUSB_HOST_U2_DEV_EXIT_LAT;
+
+	return 0;
+}
+
+/**
+ * @req:	The incoming MA USB management request packet to handle.
+ * @resp:	The MA USB management response packet to send out.
+ * @mgmt:	The MA USB HCD's management structure.
+ *
+ * This function handles management requests to the HCD. It parses the packet
+ * and makes the necessary function calls into the system.
+ *
+ * Note: this function only completes the packet type, status and
+ * request-specific data-fields. the remainder of the fields are set
+ * by mausb_rx_mgmt_req
+ */
+static int hcd_mgmt_req_switch(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt)
+{
+	int ret = 0;
+
+	switch (req->common.pkt_type) {
+
+	/* TODO: handle unimplemented request types */
+	case RemoteWakeReq:
+	case DevInitDisconnectReq:
+		break;
+	case PingReq:
+		resp->common.pkt_type   = PingResp;
+		resp->common.pkt_status = NO_ERROR;
+		break;
+	/* invalid packet type */
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int mausb_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context);
+
+/**
+ * Generates the mass_id used to initialize an MA USB device. Uses a random
+ * number generator to choose a random id between 1 and 254.
+ *
+ * Returns the random id chosen.
+ */
+static __u8 get_mass_id(void)
+{
+       __u8 id;
+
+       get_random_bytes(&id, sizeof(id));
+
+       /* Note: this function is twice as likely to pick 1 or 2 */
+       id = (id % (MASS_ID_MAX - MASS_ID_MIN + 1) + MASS_ID_MIN);
+
+       return id;
+}
+
+/**
+ * Initializes MA USB hcd roothub descriptors and ports.
+ *
+ * Always returns zero.
+ */
+static int create_mausb_hcd(struct mausb_hcd *mausb_hcd)
+{
+	if (mausb_hcd == NULL)
+		return -ENOMEM;
+
+	/* set the roothub descriptor to the proper initial values */
+	mausb_set_hub_descriptor(&mausb_hcd->root_hub.descriptor);
+	mausb_set_ss_hub_descriptor(&mausb_hcd->shared_root_hub.descriptor);
+
+	/* set the host_bos to the proper values */
+	mausb_set_host_bos(&mausb_hcd->host_bos);
+
+	/* initialize port status values */
+	mausb_init_port_status(&mausb_hcd->root_hub);
+	mausb_init_ss_port_status(&mausb_hcd->shared_root_hub);
+
+	/* initialize the MA USB device structure */
+	mausb_init_ma_device(&mausb_hcd->ma_dev, MAUSB_DEV_ADDR, get_mass_id(),
+		mausb_hcd, NULL, &hcd_mgmt_req_switch, &mausb_device_connect);
+
+	return 0;
+}
+
+/**
+ * probe function
+ */
+int mausb_probe(struct device *dev)
+{
+	int			ret = 0;
+	const char		*bus_name = MAUSB_BUS;
+	unsigned int		mausb_irqnum = 0;
+	struct usb_hcd		*usb_hcd;
+
+	/* create our USB 2.0 roothub */
+	usb_hcd = usb_create_hcd(&mausb_hc_driver, dev, bus_name);
+	if (usb_hcd == NULL) {
+		dev_err(dev, "%s: could not create USB HCD\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* create our data structure that holds MA USB data */
+	ret = create_mausb_hcd(&mhcd);
+	if (ret < 0) {
+		dev_err(dev, "%s: could not create MA USB HCD (error %i)\n",
+			__func__, ret);
+
+		return ret;
+	}
+
+	/*
+	 * Everyone exchanges pointers so we can move between data types with
+	 * minimal pointer juju.
+	 */
+	*((struct mausb_hcd **) usb_hcd->hcd_priv) = &mhcd;
+	mhcd.usb_hcd = usb_hcd;
+
+	/*
+	 * Finish initializing generic members of USB 2.0 HCD, register the bus,
+	 * request IRQ line, call driver's reset() and start() routines.
+	 */
+	ret = usb_add_hcd(usb_hcd, mausb_irqnum, IRQF_SHARED);
+	if (ret) {
+		dev_err(dev, "%s: could not add USB HCD (error %i)\n",
+			__func__, ret);
+
+		usb_remove_hcd(usb_hcd);
+
+		return ret;
+	}
+
+	/* add our USB 3.0 roothub */
+	mhcd.shared_hcd = usb_create_shared_hcd(&mausb_hc_driver, dev,
+		bus_name, usb_hcd);
+
+	if (mhcd.shared_hcd == NULL) {
+		dev_err(dev, "%s: could not create shared USB HCD\n", __func__);
+
+		usb_remove_hcd(usb_hcd);
+
+		return -ENOMEM;
+	}
+
+	ret = usb_add_hcd(mhcd.shared_hcd, mausb_irqnum, IRQF_SHARED);
+
+	if (ret) {
+		dev_err(dev, "%s: could not add shared USB HCD (error %i)\n",
+			__func__, ret);
+
+		usb_remove_hcd(usb_hcd);
+	}
+
+	return ret;
+}
+
+/**
+ * remove function
+ */
+int mausb_remove(struct device *dev)
+{
+	int			ret = 0;
+	struct usb_hcd		*hcd, *shared_hcd;
+
+	hcd = mhcd.usb_hcd;
+	shared_hcd = mhcd.shared_hcd;
+
+	if (mhcd.shared_hcd) {
+		usb_remove_hcd(mhcd.shared_hcd);
+		usb_put_hcd(mhcd.shared_hcd);
+		mhcd.shared_hcd = NULL;
+	}
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+
+	return ret;
+}
+
+/**
+ * @pkt		The incoming MA USB packet to parse.
+ * @context	The MA USB HCD's management structure.
+ *
+ * Used to transfer MA USB management packets to and from an MA USB device.
+ */
+static int mausb_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context)
+{
+	int			ret;
+	struct mausb_mgmt	*mgmt;
+	struct mausb_pkt	*pkt = mausb_pkt_from_ms_pkt_ma_dev(ms_pkt,
+					&mhcd.ma_dev, GFP_ATOMIC);
+
+	if ((NULL == context) || (NULL == pkt)) {
+		mausb_err(&mhcd, "%s: received NULL input\n", __func__);
+		return -EFAULT;
+	}
+
+	mgmt = (struct mausb_mgmt *) context;
+
+	ret = mausb_rx_mgmt(pkt, mgmt);
+
+	return ret;
+}
+
+/**
+ * @drv:	The media specific driver structure that provides an interface
+ *		for the media agnostic driver.
+ *
+ * Registers a media specific driver with the MA USB HCD.
+ */
+struct mausb_ma_drv *mausb_register_ms_driver(struct mausb_ms_drv *drv)
+{
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&mhcd.hcd_lock, irq_flags);
+	mhcd.ma_dev.ms_driver = drv;
+	spin_unlock_irqrestore(&mhcd.hcd_lock, irq_flags);
+
+	/* Open the management channel */
+	mausb_add_mgmt_channel(&mhcd.ma_dev.mgmt, drv,
+			 &mausb_transfer_mgmt_packet, &mausb_mgmt_pkt_sent);
+
+	return &mhcd.ma_dev.ma_drv;
+}
+EXPORT_SYMBOL(mausb_register_ms_driver);
+
+/**
+ * Called by a media specific driver to indicate that an MA USB device has been
+ * connected and is ready to receive MA USB packets.
+ */
+int mausb_device_connect(int on)
+{
+	int status = 0;
+	/* TODO: don't want portnum hard coded when we add more ports */
+	int portnum = 0;
+
+	/*  connection event */
+	if (on) {
+		/* reset MA USB device */
+		status = mausb_tx_dev_mgmt_req(DevResetReq, &mhcd.ma_dev.mgmt,
+			NULL, true);
+
+		if (status < 0) {
+			mausb_err(&mhcd, "%s: cannot reset MA device,"
+				" error %i\n", __func__, status);
+			return status;
+		}
+
+		/* send CapResp packet */
+		if (0 <= status) {
+			status = mausb_tx_dev_mgmt_req(CapReq,
+				&mhcd.ma_dev.mgmt, NULL, true);
+		}
+
+		if (status < 0) {
+			mausb_err(&mhcd, "%s: cannot get device capabilities,"
+				" error %i\n", __func__, status);
+			return status;
+		}
+	}
+
+	status = mausb_connect(&mhcd, portnum, on);
+
+	return status;
+}
+
+/**
+ * MA USB device creation function
+ */
+int mausb_create_dev(void)
+{
+	int ret = 0;
+
+	mhcd.dev = device_create(mausb_class, NULL,
+		MKDEV(MAUSB_MAJOR, MAUSB_MINOR), NULL, MAUSB_NAME);
+	if (IS_ERR(mhcd.dev)) {
+		ret = PTR_ERR(mhcd.dev);
+		pr_err("%s: device_create() failed with error %i\n",
+			__func__, ret);
+	}
+
+	mhcd.dev->driver = &mhcd_driver;
+
+	return ret;
+}
+
+/**
+ * MA USB device registration function
+ */
+int mausb_register_dev(struct device *dev)
+{
+	int ret = 0;
+
+	mhcd.dev->bus = &mausb_bus_type;
+	mhcd.dev->release = mausb_dev_release;
+	ret = device_register(dev);
+	if (ret) {
+		pr_err("%s: device_register() failed with error %i\n",
+			__func__, ret);
+	}
+
+	return ret;
+}
+
+/**
+ * initialization function
+ */
+int mausb_hcd_init(void)
+{
+	int ret;
+
+	ret = bus_register(&mausb_bus_type);
+	if(ret) {
+		pr_err("%s: bus_register() failed with error %i\n",
+			__func__, ret);
+		return ret;
+	}
+
+	mausb_class = class_create(THIS_MODULE, MAUSB_NAME);
+	if (IS_ERR(mausb_class)) {
+		mausb_class = NULL;
+		ret = PTR_ERR(mausb_class);
+		pr_err("%s: class_create() failed with error %i\n",
+			__func__, ret);
+		goto class_err;
+	}
+
+	ret = driver_register(&mhcd_driver);
+	if (ret) {
+		pr_err("%s: could not register driver (error %i)\n",
+			__func__, ret);
+		goto driver_err;
+	}
+
+	ret = mausb_create_dev();
+	if (ret)
+		goto dev_err;
+
+	mausb_probe(mhcd.dev);
+
+	return ret;
+
+dev_err:
+		driver_unregister(&mhcd_driver);
+
+driver_err:
+		class_destroy(mausb_class);
+		mausb_class = NULL;
+class_err:
+		bus_unregister(&mausb_bus_type);
+
+		return ret;
+}
+module_init(mausb_hcd_init);
+
+/**
+ * Exit function.
+ */
+void mausb_hcd_exit(void)
+{
+	mausb_remove(mhcd.dev);
+	device_destroy(mausb_class, MKDEV(MAUSB_MAJOR, MAUSB_MINOR));
+	driver_unregister(&mhcd_driver);
+	class_destroy(mausb_class);
+	bus_unregister(&mausb_bus_type);
+}
+module_exit(mausb_hcd_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("MA USB driver");
diff --git a/drivers/staging/mausb/drivers/mausb_hcd.h b/drivers/staging/mausb/drivers/mausb_hcd.h
new file mode 100644
index 0000000..65a9dcf
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hcd.h
@@ -0,0 +1,184 @@
+/* Name:         mausb_hcd.h
+ * Description:  header file for mausb_hcd.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_HCD_H
+#define __MAUSB_HCD_H
+
+#include <linux/spinlock.h>
+
+#include "mausb_hub.h"
+#include "mausb_pkt.h"
+#include "mausb_mem.h"
+#include "mausb_const.h"
+
+#define MAUSB_NAME "mausb"
+#define MAUSB_BUS  "mausb"
+
+#define mausb_info(mhcd, fmt, args...) \
+	dev_info(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_dbg(mhcd, fmt, args...) \
+	dev_dbg(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_warn(mhcd, fmt, args...) \
+	dev_warn(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+#define mausb_err(mhcd, fmt, args...) \
+	dev_err(mausb_hcd_to_usb_hcd(mhcd)->self.controller , fmt , ## args)
+
+/* Transfer directions */
+#define PIPE_DIR_OUT 0
+#define PIPE_DIR_IN 1
+
+/* Host BOS parameters */
+#define MAUSB_HOST_NUM_DEV_CAPS 1
+#define MAUSB_HOST_U1_DEV_EXIT_LAT 0
+#define MAUSB_HOST_U2_DEV_EXIT_LAT 0
+
+/* TEMPORARY: the mausb device will have this handle */
+#define MAUSB_DEV_ADDR 0x54
+#define MAUSB_MASS_ID  0x25
+
+struct mausb_ms_drv;
+
+/**
+ * This structure holds the information set in a get bos descriptor request.
+ *
+ * @bos_des:     Binary Object Store Descriptor, per USB2.0 Spec
+ * @ss_cap_des:  SuperSpeed Capability Descriptor, per USB3.0 Spec
+ */
+struct __attribute__((__packed__)) mausb_host_bos {
+	struct usb_bos_descriptor             bos_des;
+	struct usb_ss_cap_descriptor          ss_cap_des;
+};
+
+/**
+ * This structure holds all of the MA USB-specific data.
+ *
+ * All data listed in this structure is protected by the hcd_lock.
+ * if you want to use any of this data, you need to be in possession
+ * of this lock.
+ *
+ * @root_hub:		Contains all of the data for the USB 2.0 roothub.
+ *			This includes status, state and descriptors.
+ * @shared_root_hub:	Contains all of the data for the USB 3.0 roothub.
+ *			This includes status, state and descriptors
+ * @host_bos:		Stores the host's BOS descriptor
+ * @udev:		Pointer to the usb device we are currently sending
+ *			a packet to.
+ * @shared_hcd:		The second host controller structure for the MAUSB
+ *			driver. We need this because we do SuperSpeed, which
+ *			requires 2 root hubs.
+ * @ma_dev:		The connected MA USB device
+ * @ma_hcd_task:	Task for handling urb queue
+ * @ma_hcd_task_data:	Context for ma_hcd_task
+ * @waitq:		Event trigger for dequeue
+ * @enqueue_urb_list:	List of enqueued urbs from core
+ * @transfer_urb_list:	List of urbs awaiting ma transfer
+ * @urb_list_lock:	Lock for accessing urb lists
+ * @hcd_lock:		Lock for accessing data in this structure. note that
+ *			endpoints have their own locks. When accessing
+ *			endpoint data, this lock should NOT be held
+ * @giveback_lock:	spin lock to prevent preemption when give back an urb
+ * @resuming:		Set to 1 when HCD is resuming
+ * @disabled:		Set to 1 when hcd is disabled
+ * @dev:		Underlying device structure
+ */
+struct __attribute__((__packed__)) mausb_hcd  {
+	struct mausb_root_hub	root_hub;
+	struct mausb_root_hub	shared_root_hub;
+
+	struct mausb_host_bos	host_bos;
+
+	struct usb_device	*udev;
+
+	struct usb_hcd		*usb_hcd;
+	struct usb_hcd		*shared_hcd;
+
+	struct ma_dev		ma_dev;
+	struct task_struct	*ma_hcd_task;
+	void			*ma_hcd_task_data;
+	wait_queue_head_t	waitq;
+	struct list_head	enqueue_urb_list;
+	struct list_head	transfer_urb_list;
+	spinlock_t		urb_list_lock;
+	spinlock_t		hcd_lock;
+	spinlock_t		giveback_lock;
+	unsigned int		resuming:1;
+	unsigned int		disabled:1;
+
+	struct device		*dev;
+};
+
+/* major and minor numbers for  MA USB device */
+#define MAUSB_MAJOR	300	/* TODO: get real major number */
+#define MAUSB_MINOR	1
+
+/* Pointer conversion functions */
+inline struct mausb_hcd *usb_hcd_to_mausb_hcd(struct usb_hcd *hcd);
+inline struct usb_hcd *mausb_hcd_to_usb_hcd(struct mausb_hcd *mhcd);
+inline struct device *mausb_hcd_to_dev(struct mausb_hcd *mhcd);
+inline struct mausb_urb *usb_urb_to_mausb_urb(struct urb *urb);
+
+/* URB handling functions */
+void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status);
+
+/* Connection event function */
+int mausb_device_connect(int);
+
+/* interfaces */
+int mausb_probe(struct device *dev);
+int mausb_remove(struct device *dev);
+
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-12  8:35     ` Oliver Neukum
  2014-11-11  2:09   ` [V2 PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
                     ` (9 subsequent siblings)
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we implement USB 2.0 and 3.0 roothubs. From the host's
perspective, hub state is set and tracked just like any other USB roothub.
Likewise, requests to the roothub appear to be handled like any other wired
USB request.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_hub.c | 849 ++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_hub.h | 128 +++++
 2 files changed, 977 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_hub.h

diff --git a/drivers/staging/mausb/drivers/mausb_hub.c b/drivers/staging/mausb/drivers/mausb_hub.c
new file mode 100644
index 0000000..63c0fe4
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hub.c
@@ -0,0 +1,849 @@
+/* Name:         mausb_hub.c
+ * Description:  mausb hub structures and functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/ch9.h>
+
+#include "mausb_hub.h"
+#include "mausb_hcd.h"
+
+/**
+ * Returns MA USB roothub data structure for a USB HCD.
+ */
+struct mausb_root_hub *usb_hcd_to_roothub(struct usb_hcd *hcd)
+{
+	struct mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (usb_hcd_is_primary_hcd(hcd))
+		return &mhcd->root_hub;
+	else
+		return &mhcd->shared_root_hub;
+}
+
+/**
+ * Returns true if the given is the superspeed HCD. Note: The primary HCD is
+ * High Speed and the shared HCD is SuperSpeed.
+ */
+bool mausb_is_ss_hcd(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd))
+		return false;
+	else
+		return true;
+}
+
+/**
+ * Sets downstream port link state.
+ *
+ * @mhcd:	MA USB hcd that owns port.
+ * @state:	Link state to be set (see USB 3.0 spec for link state values).
+ * @portnum:	Port number of link state to be set.
+ */
+void set_link_state(struct mausb_root_hub *roothub, int state, int portnum)
+{
+	struct usb_port_status   *port_stat;
+
+	port_stat = &roothub->port_status[portnum];
+
+		port_stat->wPortStatus &= LINK_STATE_MASK;
+		port_stat->wPortStatus |= state;
+}
+
+/**
+ * Generates connect or disconnect event for a roothub.
+ *
+ * @hcd:	HCD associated with roothub.
+ * @do_connect: 1 for connect, 0 for disconnect.
+ * @_portnum:	Port number of connected device.
+ * @is_SS:	True if roothub is SuperSpeed or higher, otherwise false.
+ */
+int port_connect(struct usb_hcd *hcd, int do_connect, int _portnum, bool is_SS)
+{
+	int			portnum = _portnum;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	if (portnum >= MAUSB_ROOTHUB_NUM_PORTS) {
+		mausb_err(mhcd, "%s: port number %i is too large (max = %i)\n",
+			__func__, portnum, MAUSB_ROOTHUB_NUM_PORTS);
+		return -EINVAL;
+	}
+
+	/* if new connection, assign first empty port */
+	if (do_connect > 0) {
+		portnum = 0;
+		while (roothub->port_status[portnum].wPortStatus
+			& USB_PORT_STAT_CONNECTION) {
+			portnum++;
+		}
+
+		mausb_dbg(mhcd, "%s: assigned MA USB port number %d\n",
+		__func__, portnum);
+	}
+
+	/*
+	 * If new connection, we assigned portnum above, otherwise use portnum
+	 * passed in.
+	 */
+	port_stat = &roothub->port_status[portnum];
+
+	/*
+	 * Make sure port is powered. If not, clear status and disable.
+	 * Note that POWER bit is different for USB 2.0 and 3.0 hubs.
+	 */
+	if (is_SS) {
+		if ((port_stat->wPortStatus & USB_SS_PORT_STAT_POWER) == 0) {
+			port_stat->wPortStatus = 0;
+			port_stat->wPortChange = 0;
+			set_link_state(roothub, USB_SS_PORT_LS_SS_DISABLED,
+				portnum);
+
+			goto update;
+		}
+	} else {
+		if ((port_stat->wPortStatus & USB_PORT_STAT_POWER) == 0) {
+			port_stat->wPortStatus = 0;
+			port_stat->wPortChange = 0;
+
+			goto update;
+		}
+	}
+
+	/* disconnect if previously connected */
+	if (do_connect == 0 || mhcd->disabled) {
+		if ((port_stat->wPortStatus & USB_PORT_STAT_CONNECTION) == 1) {
+			port_stat->wPortStatus &= ~(USB_PORT_STAT_CONNECTION);
+			port_stat->wPortStatus &= ~(USB_PORT_STAT_ENABLE);
+			port_stat->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+			if (is_SS)
+				set_link_state(roothub,
+					USB_SS_PORT_LS_RX_DETECT, portnum);
+		}
+	}
+	/* set bits for a new connection */
+	else if ((port_stat->wPortStatus & USB_PORT_STAT_CONNECTION) == 0) {
+		port_stat->wPortStatus |= USB_PORT_STAT_ENABLE;
+		port_stat->wPortStatus |= USB_PORT_STAT_CONNECTION;
+		port_stat->wPortChange |= USB_PORT_STAT_C_CONNECTION;
+	}
+
+update:
+	mausb_dbg(mhcd, "%s: port status is 0x%x port change is 0x%x\n",
+		__func__, port_stat->wPortStatus, port_stat->wPortChange);
+
+	/* let core know if there is a change in port status */
+	if (port_stat->wPortChange) {
+		set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+		usb_hcd_poll_rh_status(hcd);
+	}
+
+	return portnum;
+}
+
+/**
+ * @mhcd:       MA USB hcd with connect/disconnect event.
+ * @portnum:	MA USB port number with event.
+ * @do_connect: Determines whether or not a connection is set or removed.
+ *
+ * Called to initiate either a device connect or disconnect event. A do_connect
+ * value of 0 clears a connection. A do_connect value greater than 0 sets a
+ * connection. A do_connect value less than 0 produces an error.
+ *
+ * Returns port number. If connection, port number is newly assigned port
+ * number, otherwise it is the port number passed in as an argument.
+ */
+int mausb_connect(struct mausb_hcd *mhcd, int portnum, int do_connect)
+{
+	struct usb_hcd		*hcd = container_of((void *)mhcd,
+					struct usb_hcd, hcd_priv);
+	struct usb_hcd		*ss_hcd = mhcd->shared_hcd;
+
+	if (!mhcd->ma_dev.ms_driver) {
+		mausb_err(mhcd, "%s: no media specific driver\n", __func__);
+		return -ENODEV;
+	}
+
+	if (do_connect < 0) {
+		mausb_err(mhcd, "%s: invalid connection request %d\n", __func__,
+			do_connect);
+		return -EINVAL;
+	}
+
+	if (mhcd->ma_dev.ma_cap.dev_type > MAUSB_DEV_TYPE_SS_HUB) {
+		mausb_err(mhcd, "%s: invalid MA USB device type %i\n", __func__,
+			mhcd->ma_dev.ma_cap.dev_type);
+		return -EINVAL;
+	}
+
+	/*
+	 * One connection event for MA devices. Connect SS and SS+ devices to
+	 * 3.0 root hub and non-SS devices to 2.0 root hub.
+	 */
+	else if (mhcd->ma_dev.ma_cap.dev_type == MAUSB_DEV_TYPE_INTEGRATED) {
+		if (!mhcd->ma_dev.speed) {
+			mausb_err(mhcd, "%s: Speed Capability Descriptor not"
+				" found - non-hub MA USB devices require"
+				" a Speed Capability Descriptor\n", __func__);
+			return -EPROTO;
+		}
+
+		mausb_dbg(mhcd, "%s: %s MA USB device\n", __func__,
+			do_connect ? "connecting" : "disconnecting");
+
+		if (mhcd->ma_dev.speed->speed == MAUSB_DEV_CAP_SPEED_SUPER ||
+		    mhcd->ma_dev.speed->speed == MAUSB_DEV_CAP_SPEED_SS_PLUS) {
+			portnum = port_connect(ss_hcd, do_connect, portnum,
+					       true);
+		} else {
+			portnum = port_connect(hcd, do_connect, portnum, false);
+		}
+	}
+
+	/*
+	 * Hubs require two connection events - one for the integrated
+	 * USB 3.0 hub and one for the integrated USB 2.0 hub.
+	 */
+	else {
+		mausb_dbg(mhcd, "%s: %s MA USB hub\n", __func__,
+			do_connect ? "connecting" : "disconnecting");
+
+		portnum = port_connect(hcd, do_connect, portnum, false);
+		portnum = port_connect(ss_hcd, do_connect, portnum, true);
+	}
+
+	return 0;
+}
+
+/**
+ * Called by usb core when polling for a port status change.
+ *
+ * @hcd:	USB HCD being polled.
+ * @buf:	Holds port status changes (if any).
+ *
+ * Returns zero if there is no status change, otherwise returns number of
+ * bytes in buf. When there is a status change on a port, the bit indexed
+ * at the port number + 1 (e.g. bit 2 for port 1) is set in the buffer.
+ */
+int mausb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	int                      i;
+	u16                      port_change = 0;
+	u32                      status = 0;
+	int                      ret = 1;
+	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	/*
+	 * Buf should never be more that 2 bytes. USB 3.0 hubs cannot have
+	 * more than 15 downstream ports.
+	 */
+	buf[0] = 0;
+	if (MAUSB_ROOTHUB_NUM_PORTS > 7) {
+		buf[1] = 0;
+		ret++;
+	}
+
+	for (i = 0; i < MAUSB_ROOTHUB_NUM_PORTS; i++) {
+		port_change = roothub->port_status[i].wPortChange;
+		if (port_change)
+			status |= (1 << (i + 1));
+	}
+
+	mausb_dbg(mhcd, "%s: hub status is 0x%x\n", __func__, status);
+
+	/* hcd might be suspended, resume if there is a status change */
+	if (mhcd->disabled == 0) {
+		if ((hcd->state == HC_STATE_SUSPENDED) && status)
+			usb_hcd_resume_root_hub(hcd);
+	}
+
+	memcpy(buf, (char *)&status, ret);
+
+	return status ? ret : 0;
+}
+
+/**
+ * Sets the bitfields in the hub descriptor of the 2.0 root hub. Always
+ * returns zero.
+ */
+int mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des)
+{
+	/* set the values to the default */
+	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
+	hub_des->bDescriptorType      = USB_DT_HUB;
+	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
+	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
+	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
+	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
+
+	return 0;
+}
+
+/**
+ * Sets the bitfields in the hub descriptor of the 3.0 root hub. Always
+ * returns zero.
+ */
+int mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des)
+{
+	/* set the values to the default */
+	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
+	hub_des->bDescriptorType      = USB_DT_SS_HUB;
+	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
+	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
+	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
+	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
+
+	/* USB3-specific parameters */
+	hub_des->u.ss.bHubHdrDecLat   = MAUSB_ROOTHUB_HDR_DEC_LAT;
+	hub_des->u.ss.wHubDelay       = MAUSB_ROOTHUB_DELAY;
+	hub_des->u.ss.DeviceRemovable = MAUSB_ALL_DEV_REMOVABLE;
+
+	return 0;
+}
+
+/**
+ * handles GetHubDescriptor requests to the root hub.
+ *
+ * @hcd:	USB HCD that owns root hub.
+ * @hub_des:    Hub descriptor to be copied.
+ * @wLength:    Maximum length that can be copied without overflowing
+ *		the buffer.
+ *
+ * Returns length of what was actually copied into the mausb hcd root hub
+ * descriptor. Note that this may be less than the total size of hub_des due
+ * to buffer size contraints.
+ */
+static int mausb_get_hub_descriptor(struct usb_hcd *hcd,
+		struct usb_hub_descriptor *hub_des, u16 wLength)
+{
+	struct mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	/* Don't overflow the buffer, and don't read more than you have. */
+	unsigned int cpyLength = min_t(u16, wLength,
+				       sizeof(struct usb_hub_descriptor));
+
+	if (mausb_is_ss_hcd(hcd))
+		memcpy(hub_des, &(mhcd->shared_root_hub.descriptor), cpyLength);
+	else
+		memcpy(hub_des, &(mhcd->root_hub.descriptor), cpyLength);
+
+	return cpyLength;
+}
+
+/**
+ * Handles requests to hub for the BOS.
+ *
+ * @ma_hcd:	MA USB HCD that owns hub.
+ * @bos:	MA USB BOS descriptor.
+ * @wLength:	Maximum length that can be copied without overflowing
+ *		the buffer.
+ *
+ * Returns length of what was actually copied into the MA USB hcd BOS
+ * descriptor. Note that this may be less than the total size of the BOS due
+ * to buffer size contraints.
+ */
+static int mausb_get_bos(struct mausb_hcd *ma_hcd,
+		struct mausb_host_bos *bos, u16 wLength)
+{
+	/* Don't overflow the buffer, and don't read more than you have. */
+	unsigned int cpyLength = min_t(u16, wLength,
+				       sizeof(struct mausb_host_bos));
+
+	memcpy(bos, &(ma_hcd->host_bos), cpyLength);
+
+	return cpyLength;
+}
+
+/**
+ * Initializes FS root hub port status values for a given MA USB roothub.
+ *
+ * All ports are initally powered and put in link state rx.detect to wait for
+ * a connection (or other event that changes link state). All other bits are
+ * cleared.
+ */
+int mausb_init_port_status(struct mausb_root_hub *mausb_rh)
+{
+	int	portnum = 0;
+
+	while (portnum < MAUSB_ROOTHUB_NUM_PORTS) {
+
+		/* set port power bit only */
+		mausb_rh->port_status[portnum].wPortStatus = 0x0;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_PORT_STAT_POWER;
+
+		/* make sure to start with no status changes */
+		mausb_rh->port_status[portnum].wPortChange = 0x0;
+		portnum++;
+	}
+
+	mausb_rh->rh_state = MAUSB_RH_RUNNING;
+
+	return 0;
+}
+
+/**
+ * Initializes SS root hub port status values for a given MA USb roothub.
+ *
+ * All ports are initally powered and put in link state rx.detect to wait for
+ * a connection (or other event that changes link state). All other bits are
+ * cleared.
+ */
+int mausb_init_ss_port_status(struct mausb_root_hub *mausb_rh)
+{
+	int	portnum = 0;
+
+	while (portnum < MAUSB_ROOTHUB_NUM_PORTS) {
+
+		/* set port power bit and put in link state rx.detect */
+		mausb_rh->port_status[portnum].wPortStatus = 0x0;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_SS_PORT_STAT_POWER;
+		mausb_rh->port_status[portnum].wPortStatus |=
+			USB_SS_PORT_LS_RX_DETECT;
+
+		/* make sure to start with no status changes */
+		mausb_rh->port_status[portnum].wPortChange = 0x0;
+		portnum++;
+	}
+
+	mausb_rh->rh_state = MAUSB_RH_RUNNING;
+
+	return 0;
+}
+
+/**
+ * Handles GetHubStatus request to root hub.
+ *
+ * @mhcd:	MA USB hcd that owns hub.
+ * @data:	Holds hub status to return to caller.
+ *
+ * Reads hub status from mhcd and gives it back to the caller via data.
+ * Returns the number of bytes copied into data.
+ */
+static int mausb_get_hub_status(struct usb_hcd *hcd, char *data)
+{
+	struct usb_hub_status   *hub_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	hub_stat = &roothub->status;
+	mausb_dbg(mhcd, "%s: hub status is 0x%x hub change is 0x%x\n",
+		__func__, hub_stat->wHubStatus, hub_stat->wHubChange);
+
+	((u16 *)data)[0] = cpu_to_le16(hub_stat->wHubStatus);
+	((u16 *)data)[1] = cpu_to_le16(hub_stat->wHubChange);
+
+	 return sizeof(hub_stat->wHubStatus) + sizeof(hub_stat->wHubChange);
+}
+
+/**
+ * Handles ClearHubFeature request to the root hub.
+ *
+ * @mhcd:	MA USB hcd that owns hub.
+ * @wValue:	Value that determines which feature is being cleared (see USB
+ *		3.0 spec for supported values).
+ *
+ * Returns 0 if sucessful, otherwise returns error to indicate invalid request.
+ */
+static int mausb_clear_hub_feature(struct usb_hcd *hcd, u16 wValue)
+{
+	int			err = 0;
+	struct usb_hub_status	*hub_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	hub_stat = &roothub->status;
+
+	switch (wValue) {
+	case C_HUB_LOCAL_POWER:
+		mausb_dbg(mhcd, "clearing HUB_LOCAL_POWER\n");
+		hub_stat->wHubChange &= ~(HUB_STATUS_LOCAL_POWER);
+		break;
+	case C_HUB_OVER_CURRENT:
+		mausb_dbg(mhcd, "clearing HUB_OVER_CURRENT\n");
+		hub_stat->wHubChange &= ~(HUB_STATUS_OVERCURRENT);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles GetPortStatus request to root hub.
+ *
+ * @mhcd:    	MA USB hcd that owns hub.
+ * @portnum:	Port number for which status is requested.
+ * @data:    	Holds port status to return to caller.
+ *
+ * Reads port status from mhcd and returns it to caller via data. Also
+ * completes a port reset.
+ *
+ * Returns the number of bytes copied into data.
+ */
+static int mausb_get_port_status(struct usb_hcd *hcd, int portnum, char *data)
+{
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	/*
+	 * Note: from USB core perspective ports are 1-indexed, mhcd uses
+	 * zero-indexing.
+	 */
+	port_stat = &roothub->port_status[portnum - 1];
+
+	/*
+	 * USB core sends a GetPortStatus request to complete a port reset.
+	 * After reset, port is enabled and link state is U0 (3.0 only).
+	 */
+	if (port_stat->wPortStatus & USB_PORT_STAT_RESET) {
+		port_stat->wPortStatus &= ~(USB_PORT_STAT_RESET);
+		port_stat->wPortStatus |= USB_PORT_STAT_ENABLE;
+
+		if (mausb_is_ss_hcd(hcd))
+			set_link_state(roothub, USB_SS_PORT_LS_U0, portnum - 1);
+	}
+
+	((u16 *)data)[0] = cpu_to_le16(port_stat->wPortStatus);
+	((u16 *)data)[1] = cpu_to_le16(port_stat->wPortChange);
+
+	mausb_dbg(mhcd, "%s: Port status is 0x%x Port change is 0x%x\n",
+		__func__, ((u16 *)data)[0], port_stat->wPortChange);
+
+	return sizeof(port_stat->wPortStatus) + sizeof(port_stat->wPortChange);
+}
+
+/**
+ * Handles SetPortFeature request to root hub.
+ *
+ * @mhcd:    	MA USB hcd that owns hub.
+ * @portnum:	Port number for which feature set is requested (port
+ *		number is from usb core perspective, i.e. not zero-indexed).
+ * @wValue:	Feature to be set (see USB 3.0 spec for supported values).
+ * @wIndex:	Contains link state to be set (ignored for requests other
+ *              than set link state).
+ *
+ * Sets the bit associated with a particular feature in the status bit field
+ * of the port specified by portnum. Note that ports are zero indexed in the
+ * hub, but indexed starting with one in the usb core (e.g. port 2 from the
+ * core's perspective is port 1 to the hub).
+ *
+ * Returns zero for all supported requests. Returns an error value if a feature
+ * is not supported.
+ */
+static int mausb_set_port_feature(struct usb_hcd *hcd, int portnum, u16 wValue,
+		u16 wIndex)
+{
+	int			err = 0;
+	u8			link_state = 0;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	*roothub = usb_hcd_to_roothub(hcd);
+
+	port_stat = &roothub->port_status[portnum - 1];
+
+	switch (wValue) {
+	case USB_PORT_FEAT_RESET:
+		mausb_dbg(mhcd, "setting PORT_RESET feature\n");
+		port_stat->wPortStatus |= USB_PORT_STAT_RESET;
+		port_stat->wPortChange |= USB_PORT_STAT_C_RESET;
+		break;
+	case USB_PORT_FEAT_BH_PORT_RESET:
+		mausb_dbg(mhcd, "setting BH_PORT_RESET\n");
+		break;
+	case USB_PORT_FEAT_POWER:
+		mausb_dbg(mhcd, "setting PORT_POWER feature\n");
+		port_stat->wPortStatus |= USB_SS_PORT_STAT_POWER;
+		set_link_state(roothub, USB_SS_PORT_LS_RX_DETECT, portnum - 1);
+		break;
+	case USB_PORT_FEAT_U1_TIMEOUT:
+		mausb_dbg(mhcd, "setting PORT_U1_TIMEOUT\n");
+		break;
+	case USB_PORT_FEAT_U2_TIMEOUT:
+		mausb_dbg(mhcd, "setting PORT_U2_TIMEOUT\n");
+		break;
+	case USB_PORT_FEAT_LINK_STATE:
+		link_state = wIndex >> 8;
+		if (link_state == SS_DISABLED) {
+			mausb_dbg(mhcd, "setting link state to ss.disabled\n");
+			mhcd->disabled = 1;
+			clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+			set_link_state(roothub, USB_SS_PORT_LS_SS_DISABLED,
+				portnum - 1);
+			mausb_connect(mhcd, portnum - 1, 0);
+		}
+
+		else if (link_state == RX_DETECT) {
+			mausb_dbg(mhcd, "setting link state to rx.detect\n");
+			mhcd->disabled = 0;
+			set_link_state(roothub, USB_SS_PORT_LS_RX_DETECT,
+				portnum - 1);
+		}
+	break;
+	case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+		mausb_dbg(mhcd, "setting PORT_REMOTE_WAKE_MASK\n");
+	break;
+	case USB_PORT_FEAT_FORCE_LINKPM_ACCEPT:
+		mausb_dbg(mhcd, "setting FORCE_LINKPM_ACCEPT\n");
+	break;
+	default:
+		 err = -EINVAL;
+	break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles ClearPortFeature request to the root hub.
+ *
+ * @mhcd:     	MA USB hcd that owns hub.
+ * @portnum:	Port number for which feature clear is requested (port
+ *              number is from usb core perspective, i.e. not zero-indexed).
+ * @wValue:	Feature to clear (see USB 3.0 spec for supported values).
+ *
+ * Clears the bit associated with a particular feature in the status bit field
+ * of the port specified by portnum. Note that ports are zero indexed in the
+ * hub, but indexed starting with one in the usb core (e.g. port 2 from the
+ * core's perspective is port 1 to the hub).
+ *
+ * Returns zero for all supported requests. Returns an error value if a feature
+ * is not supported.
+ */
+static int mausb_clear_port_feature(struct usb_hcd *hcd, int portnum,
+		u16 wValue)
+{
+	int			 err = 0;
+	struct usb_port_status	*port_stat;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
+
+	port_stat = &roothub->port_status[portnum - 1];
+
+	switch (wValue) {
+	case USB_PORT_FEAT_POWER:
+		mausb_dbg(mhcd, "clearing PORT_POWER feature\n");
+		port_stat->wPortStatus &= ~(USB_SS_PORT_STAT_POWER);
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		mausb_dbg(mhcd, "clearing PORT_C_CONNECTION feature\n");
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_CONNECTION);
+		break;
+	case USB_PORT_FEAT_C_RESET:
+		mausb_dbg(mhcd, "clearing PORT_RESET feature\n");
+		port_stat->wPortStatus &= ~(USB_PORT_STAT_RESET);
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_RESET);
+		/* prevent excessive polling after reset */
+		clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		mausb_dbg(mhcd, "clearing PORT_OVER_CURRENT feature\n");
+		port_stat->wPortChange &= ~(USB_PORT_STAT_C_OVERCURRENT);
+	case USB_PORT_FEAT_C_PORT_LINK_STATE:
+	case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
+	case USB_PORT_FEAT_C_BH_PORT_RESET:
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * Handles getDescriptor requests to the roothub.
+ *
+ * @ma_hcd:	MA USB hcd that owns hub.
+ * @wValue:	Contains descriptor type in upper byte (see USB 3.0 spec for
+ *              descriptor types).
+ * @buf:	Holds descriptor to return to caller.
+ * @wLength:	Expected descriptor length.
+ *
+ * If successful, returns actual length of descriptor in buf. Otherwise returns
+ * error value.
+ */
+static int mausb_get_descriptor(struct mausb_hcd *ma_hcd, u16 wValue,
+		char *buf, u16 wLength)
+{
+	int	ret;
+
+	/*
+	 * per USB spec, section 9.4.3, the DT is contained in the upper byte
+	 * of wValue
+	 */
+	u8  bDesType = (wValue >> 8);
+
+	switch (bDesType) {
+	case USB_DT_DEVICE:
+		mausb_err(ma_hcd, "USB_DT_DEVICE not supported\n");
+		ret = -EPIPE;
+		break;
+	case USB_DT_CONFIG:
+		ret = 0;
+		break;
+	case USB_DT_BOS:
+		ret = mausb_get_bos(ma_hcd, (struct mausb_host_bos *) buf,
+			wLength);
+		mausb_dbg(ma_hcd, "%s: bos copied to buffer, wTotalLength %x\n",
+			__func__,
+			((struct mausb_host_bos *) buf)->bos_des.wTotalLength);
+		break;
+	case USB_DT_STRING:
+		ret = 0;
+		break;
+	default: /* invalid request */
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Handles requests from usb core to hub.
+ *
+ * @hcd:	USB hcd that owns hub.
+ * @typeReq:	Request type (see USB 3.0 spec for request types).
+ * @wValue:	Feature selector for hub/port feature requests,
+ *		descriptor type and index for hub descriptor requests,
+ *		hub depth for hub depth requests,zero for all other requests.
+ * @wIndex:	Port number for port requests, zero or language id for hub
+ *		descriptor requests, zero for all other requests.
+ * @buf:	Buffer for requested descriptor or status (if applicable).
+ * @wLength:	Descriptor length for descriptor requests, otherwise zero.
+ *
+ * Called by the USB core to make a request to the root hub. mausb_hub_control
+ * parses the request and routes it to the appropriate mausb helper function.
+ *
+ * If successful, returns descriptor length for descriptor request or zero for
+ * other requests. Otherwise returns error value.
+ */
+int mausb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+		u16 wIndex, char *buf, u16 wLength)
+{
+	int		err = 0;
+	int		portnum = (wIndex & 0xFF);
+	struct		mausb_hcd *mhcd = usb_hcd_to_mausb_hcd(hcd);
+
+	if (portnum > MAUSB_ROOTHUB_NUM_PORTS) {
+		mausb_err(mhcd, "port number %d is invalid\n", portnum);
+		return -EINVAL;
+	}
+
+	switch (typeReq) {
+	case MAUSB_REQ_GET_DES:
+		err = mausb_get_descriptor(usb_hcd_to_mausb_hcd(hcd),
+			wValue, buf, wLength);
+		err = sizeof(struct mausb_host_bos);
+		break;
+	case ClearHubFeature:
+		mausb_dbg(mhcd, "clearing hub feature %d\n", wValue);
+		err = mausb_clear_hub_feature(hcd, wValue);
+		break;
+	case ClearPortFeature:
+		mausb_dbg(mhcd, "clearing port %d feature %d\n", portnum,
+			wValue);
+		err = mausb_clear_port_feature(hcd, portnum, wValue);
+		break;
+	case GetHubDescriptor:
+		err = mausb_get_hub_descriptor(hcd,
+			(struct usb_hub_descriptor *) buf, wLength);
+		break;
+	case GetHubStatus:
+		mausb_dbg(mhcd, "getting hub status\n");
+		err = mausb_get_hub_status(hcd, buf);
+		break;
+	case GetPortStatus:
+		mausb_dbg(mhcd, "getting port %d status\n", portnum);
+		err = mausb_get_port_status(hcd, portnum, buf);
+		break;
+	/* SetHubFeature support is optional (only used for diagnostics) */
+	case SetHubFeature:
+		err = 0;
+		break;
+	case SetPortFeature:
+		mausb_dbg(mhcd, "setting port %d feature %d\n", portnum,
+			wValue);
+		mausb_set_port_feature(hcd, portnum, wValue, wIndex);
+		break;
+	case SetHubDepth:
+		err = 0;
+		break;
+	case GetPortErrorCount:
+		err = 0;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb driver");
diff --git a/drivers/staging/mausb/drivers/mausb_hub.h b/drivers/staging/mausb/drivers/mausb_hub.h
new file mode 100644
index 0000000..7670c1b
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_hub.h
@@ -0,0 +1,128 @@
+/* name:	 mausb_hub.h
+ * description:  header file for mausb hub
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_HUB_H
+#define __MAUSB_HUB_H
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+
+/* root hub Parameters */
+#define MAUSB_ROOTHUB_CHAR (HUB_CHAR_LPSM | HUB_CHAR_INDV_PORT_OCPM)
+#define MAUSB_ROOTHUB_NUM_PORTS		1
+#define MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD 0
+#define MAUSB_ROOTHUB_CONTR_CURRENT     0
+#define MAUSB_ROOTHUB_HDR_DEC_LAT       0	/* < 0 uS */
+#define MAUSB_ROOTHUB_DELAY             0	/* 0 nS */
+#define MAUSB_ALL_DEV_REMOVABLE		0x0000  /* All devices are removable */
+
+/* per USB3 spec, section 9.4.3 */
+#define MAUSB_REQ_GET_DES (0x8000 | USB_REQ_GET_DESCRIPTOR)
+
+/* link state selectors for set_port_feature request to root hub */
+#define SS_DISABLED	4
+#define RX_DETECT	5
+
+/* mask used to clear port link state bits (bits 5-8) in wPortStatus */
+#define	LINK_STATE_MASK			0xFE1F
+
+/* forward declarations */
+struct mausb_root_hub;
+struct mausb_hcd;
+
+/* root hub states */
+enum mausb_rh_state {
+	MAUSB_RH_RESETTING,
+	MAUSB_RH_SUSPEND,
+	MAUSB_RH_RUNNING
+};
+
+/**
+ * Contains all the structures required to emulate a root hub. One instance
+ * exists per root hub.
+ */
+struct __attribute__((__packed__)) mausb_root_hub {
+
+	/* hub parameters */
+	struct usb_hub_descriptor descriptor;
+	struct usb_hub_status     status;
+
+	/* port parameters*/
+	struct usb_port_status    port_status[MAUSB_ROOTHUB_NUM_PORTS];
+
+	/* root hub state */
+	enum   mausb_rh_state     rh_state;
+
+};
+
+/* function declarations */
+bool    mausb_is_ss_hcd(struct usb_hcd *hcd);
+int	mausb_hub_status_data(struct usb_hcd *hcd, char *buf);
+int	mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des);
+int	mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des);
+int	mausb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+		u16 wIndex, char *buf, u16 wLength);
+int	mausb_init_port_status(struct mausb_root_hub *mausb_rh);
+int	mausb_init_ss_port_status(struct mausb_root_hub *mausb_rh);
+int	mausb_connect(struct mausb_hcd *hcd, int portnum, int do_connect);
+struct  mausb_root_hub *usb_hcd_to_roothub(struct usb_hcd *hcd);
+
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  4:38     ` Greg KH
  2014-11-11  2:09   ` [V2 PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
                     ` (8 subsequent siblings)
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we create, store and handle endpoint and device structures
that are specific to the MA USB drivers. Each MA USB structure maps 1:1
with it's corresponding USB structure (e.g. there is one MA USB endpoint
per USB endpoint).

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_const.h    | 109 ++++
 drivers/staging/mausb/drivers/mausb_mem-host.c | 402 ++++++++++++
 drivers/staging/mausb/drivers/mausb_mem-host.h |  74 +++
 drivers/staging/mausb/drivers/mausb_mem.c      | 842 +++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_mem.h      | 509 +++++++++++++++
 drivers/staging/mausb/drivers/mausb_state.h    | 184 ++++++
 6 files changed, 2120 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_const.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem-host.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mem.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_state.h

diff --git a/drivers/staging/mausb/drivers/mausb_const.h b/drivers/staging/mausb/drivers/mausb_const.h
new file mode 100755
index 0000000..1089f81
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_const.h
@@ -0,0 +1,109 @@
+/* Name:	mausb_const.h
+ * Description: This header describes the Media Agnostic USB constants
+ *              that must be known by the both the host and device side drivers.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_CONST_H
+#define __MAUSB_CONST_H
+
+/* MA USB protocol constants per Table 68 of the MA USB Spec */
+#define MAUSB_DATA_CHANNEL_DELAY	400	/* temp value */
+#define MAUSB_MGMT_CHANNEL_DELAY	((100 * HZ)/1000 + 1)
+#define MAUSB_MGMT_RESPONSE_DELAY	((5 * HZ)/1000 + 1) /* 5 msec */
+#define MAUSB_MGMT_RT_DELAY \
+	((MAUSB_MGMT_RESPONSE_DELAY + (2 * MAUSB_MGMT_CHANNEL_DELAY)))
+#define MAUSB_TRANSFER_RESPONSE_TIME	10	/* 10 msec */
+#define MAUSB_TRANSFER_TIMEOUT \
+	(MAUSB_TRANSFER_RESPONSE_TIME + (2 * MAUSB_DATA_CHANNEL_DELAY))
+#define MAUSB_TRANSFER_KEEP_ALIVE \
+	(MAUSB_TRANSFER_RESPONSE_TIME + MAUSB_DATA_CHANNEL_DELAY)
+#define MAUSB_DEFAULT_KEEP_ALIVE	 0
+#define MAUSB_MAX_TRANSFER_LIFETIME	 1000	/* 1 sec */
+#define MAUSB_TRANSFER_REPEAT_TIME	 10	/* 10 msec */
+
+#define MAUSB_MAX_REQ_ID		 ((1 << 8) - 1)
+#define MAUSB_MAX_SEQ_NUM		 ((1 << 24) - 1)
+#define MAUSB_MAX_DIALOG_TOKEN		 ((1 << 10) - 1)
+#define MAUSB_MIN_CONTROL_BUF_SIZE	 4104	/* Bytes */
+
+
+/* MA USB protocol variables per Table 69 of the MA USB Spec */
+#define MAUSB_BULK_TRANSFER_RETRIES	 10	/* min value is 5 */
+#define MAUSB_CONTROL_TRANSFER_RETRIES	 10	/* min value is 5 */
+#define MAUSB_INTERRUPT_TRANSFER_RETRIES 10	/* min value is 3 */
+#define MAUSB_MGMT_TRANSFER_RETRIES	 4      /* min value is 4 */
+#define MAUSB_TRANSFER_SETUP_RETRIES	 4	/* min value is 4 */
+
+
+/* MA USB constants not explicitly defined in MA USB Spec */
+#define MAUSB_HALF_REQ_ID		 ((MAUSB_MAX_REQ_ID + 1) >> 2)
+#define MAUSB_HALF_SEQ_NUM		 ((MAUSB_MAX_SEQ_NUM + 1) >> 2)
+#define MAUSB_MAX_OUTSTANDING_SEQ_NUM	 (1 << 23)
+
+/* Largest packet size (in bytes) that the medium can handle */
+#define MAUSB_MAX_PACKET_SIZE	300
+
+/* Used to parse get_status control requests */
+#define EP_REQ (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+#define EP_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
+#define DEV_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+#define INTF_IN_REQ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
+
+/* Used for generating the mass_id for the device */
+#define MASS_ID_MIN	1
+#define MASS_ID_MAX	254
+
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_mem-host.c b/drivers/staging/mausb/drivers/mausb_mem-host.c
new file mode 100644
index 0000000..7ba0ec5
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem-host.c
@@ -0,0 +1,402 @@
+/* Name:	mausb_mem-host.c
+ * Description: Contains hostside-specific memory functions, as well as
+ *              wrappers for functions in mausb_mem.c.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include <linux/kthread.h>
+
+#include "mausb_hcd.h"
+#include "mausb_mem-host.h"
+#include "mausb_mem.h"
+#include "mausb_tx.h"
+#include "mausb_mgmt.h"
+
+/**
+ * Returns a pointer to the media agnostic data for a given endpoint.
+ */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep)
+{
+	return (struct mausb_host_ep *) ep->hcpriv;
+}
+
+/**
+ * Returns the number of urbs currently in the MA USB HCD. Will return 0 if the
+ * MA USB HCD is empty or a negative errno if an error occurs.
+ */
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd)
+{
+	int			count = 0;
+	struct mausb_host_ep	*ma_ep;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_urb	*maurb;
+	unsigned long		irq_flags;
+
+	/* for every device */
+	spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &mhcd->ma_dev.dev_list, dev_list) {
+		spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+		/* for every endpoint */
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+		list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+			spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+			/* for every urb */
+			spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+			list_for_each_entry(maurb, &ma_ep->urb_list, urb_list) {
+				++count;
+			}
+
+			spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+			spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+		}
+
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
+	}
+
+	spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
+
+	return count;
+}
+
+/**
+ * This function removes a device data from the hcd. All endpoints belonging
+ * to this device are also removed from the hcd and released (including EP0).
+ */
+void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev = mausb_find_dev_host(ma_dev, dev);
+	struct mausb_host_ep	*ep0 = list_first_entry(&mausb_dev->ep_list,
+					struct mausb_host_ep, ep_list);
+
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "%s: USB device #%i not found\n",
+			__func__, dev->devnum);
+		return;
+	}
+
+	ep0->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+
+	/* inactivate EP0 handle */
+	mausb_tx_dev_mgmt_req_ep(EPInactivateReq, &mhcd->ma_dev.mgmt,
+		mausb_dev, true, ep0);
+
+	/* delete remaining EP Handles */
+	mausb_tx_dev_mgmt_req(EPHandleDeleteReq, &mhcd->ma_dev.mgmt,
+		mausb_dev, MAUSB_HOST);
+
+	mausb_tx_dev_mgmt_req(USBDevDisconnectReq, &ma_dev->mgmt,
+		mausb_dev, MAUSB_HOST);
+
+	mausb_internal_free_dev(ma_dev, mausb_dev);
+
+	return;
+}
+
+/*
+ * Adds an endpoint to the specified device.
+ *
+ * This function allocates private endpoint data and adds the given endpoint
+ * to the given device. In the mausb_hcd, devices hold their endpoints in a
+ * linked list.
+ */
+int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep)
+{
+	int			status;
+	char			*ep_type;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev;
+	struct mausb_ms_drv	*ms_driver = ma_dev->ms_driver;
+	struct mausb_host_ep	*ma_ep;
+
+	/* don't need to do anything for root hub */
+	if ((NULL == dev->parent) && (&dev->ep0 != ep))
+		return 0;
+
+	mausb_dev = mausb_find_dev_host(ma_dev, dev);
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "unable to add endpoint: USB device #%i not"
+			" found\n", dev->devnum);
+		return -ENODEV;
+	}
+
+	status = mausb_internal_add_ep(mausb_dev, ep, NULL, &ma_ep,
+		&host_transfer_timeout, GFP_KERNEL);
+
+	if (status < 0) {
+		mausb_err(mhcd, "could not add endpoint: error %i\n", status);
+		return status;
+	}
+
+	/* need ms driver before adding endpoint */
+	if (NULL == ms_driver)
+		return -ENODEV;
+
+	/* for debug messages */
+	switch (usb_endpoint_type(&ep->desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ep_type = "control";
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ep_type = "bulk";
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ep_type = "interrupt";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		ep_type = "isochronous";
+		break;
+	default:
+		ep_type = "unknown";
+	}
+
+	/* set up control endpoint data channel */
+	if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_CONTROL) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_control_transferRequest);
+	}
+	/* set up bulk IN endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK
+		&& usb_endpoint_dir_in(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_IN_transferRequest);
+	}
+	/* set up bulk OUT endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK
+		&& usb_endpoint_dir_out(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_OUT_transferRequest);
+	}
+	/* set up an interrupt IN endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_INT
+		&& usb_endpoint_dir_in(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_IN_transferRequest);
+	}
+	/* set up an interrupt OUT endpoint data channel */
+	else if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_INT
+		&& usb_endpoint_dir_out(&ep->desc)) {
+		status = mausb_add_data_channel(ms_driver, ma_ep,
+			&complete_OUT_transferRequest);
+	} else {
+		mausb_err(mhcd,
+			"%s: attempted to add channel for ep %i of unsupported"
+			" type\n", __func__, usb_endpoint_num(&ep->desc));
+		return -EOPNOTSUPP;
+	}
+
+	if (status < 0) {
+		mausb_err(mhcd, "cannot add %s channel for ep %i: error %i\n",
+			ep_type, usb_endpoint_num(&ep->desc), status);
+		/* cleanup endpoint */
+		mausb_internal_drop_ep(ma_ep);
+	} else {
+		mausb_dbg(mhcd, "%s: added %s channel for ep %i\n", __func__,
+			ep_type, usb_endpoint_num(&ep->desc));
+	}
+
+	return status;
+}
+
+/*
+ * Removes an endpoint from the specified device.
+ *
+ * This function removes the given endpoint from the given device and releases
+ * private endpoint data. In the mausb_hcd, devices hold their endpoints in
+ * a linked list.
+ *
+ * TODO: determine & implement proper behavior when endpoint is not
+ *       associated with given device (or is associated with a different
+ *       device)
+ */
+int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep)
+{
+	int			ret = 0;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct mausb_host_ep	*ma_ep = usb_to_ma_endpoint(ep);
+	struct mausb_dev	*ma_dev;
+	struct mausb_urb	*ma_urb, *next_urb;
+	unsigned long		irq_flags;
+
+	if (NULL == ma_ep) {
+		mausb_err(mhcd, "%s: cannot find data for endpoint at %p\n",
+			__func__, ep);
+		return -ENODEV;
+	}
+
+	ma_dev = ma_ep->mausb_dev;
+
+	mausb_dbg(mhcd, "dropping endpoint at %p to USB device #%i\n", ep,
+		dev->devnum);
+
+	ret = mausb_tx_dev_mgmt_req_ep(CancelTransferReq, &mhcd->ma_dev.mgmt,
+		ma_dev, true, ma_ep);
+
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+
+	ret = mausb_tx_dev_mgmt_req_ep(EPInactivateReq, &mhcd->ma_dev.mgmt,
+		ma_dev, true, ma_ep);
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+	list_for_each_entry_safe(ma_urb, next_urb, &ma_ep->urb_list, urb_list) {
+
+		mausb_unlink_giveback_urb(ma_urb, -ECONNRESET);
+	}
+
+	if (!list_empty(&ma_ep->urb_list)) {
+		mausb_err(mhcd, "%s: could not drop all urbs for ma_ep at %p\n",
+			__func__, ma_ep->ep);
+	}
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * This function allocates a new device and adds it onto the MA device's linked
+ * list of usb devices. It also allocates endpoint data for the control
+ * endpoint (EP0).
+ *
+ * Returns 1 on success or 0 on failure.
+ */
+int mausb_alloc_dev(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	int			status = 0;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev;
+
+	mausb_dev = mausb_internal_alloc_dev(ma_dev, dev, NULL);
+	if (NULL == mausb_dev)
+		return 0;
+
+	/* add EP0 */
+	mausb_dbg(mhcd, "%s: adding EP0 . . .\n", __func__);
+	status = mausb_add_endpoint(hcd, dev, &dev->ep0);
+
+	/*
+	 * Don't add send the EP Request yet, usbcore hasn't set
+	 * the ep0 descriptor. Wait until a datapacket is sent.
+	 */
+
+	if (status >= 0)
+		return 1;
+
+	/* TODO: drop endpoint here if failure */
+	mausb_free_dev(hcd, dev);
+	mausb_err(mhcd, "%s: could not add EP0 %i\n", __func__, status);
+	return 0;
+}
+
+/**
+ * USB core calls the HCD's check_bandwidth function immediately after adding
+ * or deleting endpoints.
+ */
+int mausb_check_bandwidth(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	int			status;
+	struct mausb_hcd	*mhcd = usb_hcd_to_mausb_hcd(hcd);
+	struct ma_dev		*ma_dev = &mhcd->ma_dev;
+	struct mausb_dev	*mausb_dev = mausb_find_dev_host(ma_dev, dev);
+
+	/* don't do anything if roothub */
+	if (NULL == dev->parent)
+		return 0;
+
+	if (NULL == mausb_dev) {
+		mausb_err(mhcd, "%s: could not find data for USB device #%i\n",
+			__func__, dev->devnum);
+		return -ENODEV;
+	}
+
+	/* delete the old endpoints (if applicable) */
+	status = mausb_tx_dev_mgmt_req(EPHandleDeleteReq, &ma_dev->mgmt,
+					mausb_dev, MAUSB_HOST);
+
+	/* TODO: error checking (suppose the EPHandleDelete fails...) */
+
+	/* add the new endpoints (if applicable) */
+	status = mausb_tx_dev_mgmt_req(EPHandleReq, &ma_dev->mgmt, mausb_dev,
+		MAUSB_HOST);
+
+	if (-ENODEV == status) /* no endpoints were applicable */
+		status = 0;
+
+	return status;
+}
+
+/**
+ * This function will be called if mausb_add_endpoint(), mausb_drop_ep(),
+ * or mausb_check_bandwidth returns with an error. It is supposed to revert
+ * a device to a previously good schedule. We assume any schedule will work,
+ * so we should, in theory, never have to revert to a previous schedule.
+ */
+void mausb_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *dev)
+{
+	mausb_dbg(usb_hcd_to_mausb_hcd(hcd),
+		"resetting bandwidth for USB edvice #%i\n", dev->devnum);
+	return;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_mem-host.h b/drivers/staging/mausb/drivers/mausb_mem-host.h
new file mode 100644
index 0000000..9df6c1f
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem-host.h
@@ -0,0 +1,74 @@
+/* Name:	mausb_mem-host.h
+ * Description: header for mausb_mem-host.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MEM_HOST_H
+#define __MAUSB_MEM_HOST_H
+
+/* endpoint/device helper functions */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep);
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd);
+
+/* USB core interfaces */
+int mausb_alloc_dev(struct usb_hcd *hcd, struct usb_device *dev);
+void mausb_free_dev(struct usb_hcd *hcd, struct usb_device *dev);
+int mausb_add_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep);
+int mausb_drop_endpoint(struct usb_hcd *hcd, struct usb_device *dev,
+		struct usb_host_endpoint *ep);
+int mausb_check_bandwidth(struct usb_hcd *hcd, struct usb_device *dev);
+void mausb_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *dev);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_mem.c b/drivers/staging/mausb/drivers/mausb_mem.c
new file mode 100644
index 0000000..e378e2d
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem.c
@@ -0,0 +1,842 @@
+/* Name:	mausb_mem.c
+ * Description: Handles all of the dynamic data structures for the host
+ *              controller, including any data that needs to exist
+ *              on a per-device, per-endpoint, or per-transfer basis.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/kthread.h>
+
+#include "mausb_mem.h"
+#include "mausb_mgmt.h"
+#include "mausb_tx.h"
+#include "mausb_pkt.h"
+#include "mausb_const.h"
+#include "mausb_hcd.h"
+
+struct mausb_host_ep *mausb_state_to_ep(struct mausb_ep_state *state)
+{
+	return container_of(state, struct mausb_host_ep, state);
+}
+EXPORT_SYMBOL(mausb_state_to_ep);
+
+struct mausb_hcd *mausb_host_ep_to_mahcd(struct mausb_host_ep *ep)
+{
+	return ep->mausb_dev->ma_dev->mhcd;
+}
+EXPORT_SYMBOL(mausb_host_ep_to_mahcd);
+
+struct mausb_udc *mausb_host_ep_to_maudc(struct mausb_host_ep *ep)
+{
+	return ep->mausb_dev->ma_dev->maudc;
+}
+EXPORT_SYMBOL(mausb_host_ep_to_maudc);
+
+struct ma_dev *context_to_ma_dev(void *context)
+{
+	return (struct ma_dev *) context;
+}
+
+/*
+ * Finds the media-agnostic data for a given device.
+ *
+ * @ma_dev:	The MA USB device the USB device is located behind.
+ * @dev:	The USB device to find.
+ * @handle:	The MA USB device handle of USB device to find.
+ * @gadget:	The USB gadget device to find.
+ *
+ * Returns a pointer to the media agnostic data for a USB device given one or
+ * more parameters. Returns NULL if the device cannot be found.
+ */
+struct mausb_dev *mausb_find_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, unsigned long *handle,
+		struct usb_gadget *gadget)
+{
+	struct mausb_dev *mausb_dev;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &ma_dev->dev_list, dev_list) {
+
+		/* if found */
+		if ((NULL != dev && mausb_dev->dev == dev) ||
+			(NULL != gadget && mausb_dev->gadget == gadget) ||
+			(NULL != handle && mausb_dev->dev_handle == *handle)) {
+			spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+			return mausb_dev;
+		}
+	}
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	/* device not found */
+	return NULL;
+}
+
+struct mausb_dev *mausb_find_dev_host(struct ma_dev *ma_dev,
+		struct usb_device *dev)
+{
+	return mausb_find_dev(ma_dev, dev, NULL, NULL);
+}
+EXPORT_SYMBOL(mausb_find_dev_host);
+
+/**
+ * Returns true if usb_endpoint descriptors are the same.
+ */
+static bool mausb_ep_desc_eq(const struct usb_endpoint_descriptor *desc1,
+		const struct usb_endpoint_descriptor *desc2)
+{
+	return ((desc1->bLength == desc2->bLength)
+		&& (desc1->bDescriptorType  == desc2->bDescriptorType)
+		&& (desc1->bEndpointAddress == desc2->bEndpointAddress)
+		&& (desc1->bmAttributes     == desc2->bmAttributes)
+		&& (desc1->wMaxPacketSize   == desc2->wMaxPacketSize));
+}
+
+/**
+ * Finds the media agnostic data for an endpoint given one or more parameters.
+ *
+ * @ep:			USB host endpoint to find MA USB endpoint for.
+ * @dev_ep:		USB device endpoint to find MA USB endpoint for.
+ * @handle:		Endpoint handle of MA USB endpoint.
+ * @mausb_dev:		The MA USB device the endpoint belongs to.
+ * @ep_desc:		endpoint descriptor for USB endpoint.
+ * @address:		MA USB endpoint address.
+ *
+ * Returns a pointer to the media agnostic data for the endpoint or NULL if
+ * the device cannot be found.
+ */
+static struct mausb_host_ep *mausb_find_ep(struct usb_host_endpoint *ep,
+		struct usb_ep *dev_ep, struct mausb_ep_handle *handle,
+		struct mausb_dev *mausb_dev,
+		const struct usb_endpoint_descriptor *ep_desc,
+		u8 address)
+{
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+
+		/* if found */
+		if ((NULL != dev_ep && ma_ep->dev_ep == dev_ep) ||
+			(NULL != ep && ma_ep->ep == ep) ||
+			(NULL != handle
+			 && ma_ep->ep_handle_state != MAUSB_EP_HANDLE_UNASSIGNED
+			 && ma_ep->ep_handle.handle == handle->handle) ||
+			(NULL != ep_desc && NULL != ma_ep->ep
+			 && mausb_ep_desc_eq(ep_desc, &ma_ep->ep->desc)) ||
+			(NULL != ep_desc && NULL != ma_ep->dev_ep &&
+			 NULL != ma_ep->dev_ep->desc
+			 && mausb_ep_desc_eq(ep_desc, ma_ep->dev_ep->desc)) ||
+			(address != 0 && NULL != ma_ep->dev_ep &&
+			 address == ma_ep->dev_ep->address)) {
+
+			spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+			return ma_ep;
+		}
+	}
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	/* endpoint not found */
+	return NULL;
+}
+
+struct mausb_host_ep *mausb_find_ep_dev(struct usb_ep *dev_ep,
+			struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(NULL, dev_ep, NULL, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_dev);
+
+struct mausb_host_ep *mausb_find_ep_host(struct usb_host_endpoint *ep,
+	struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(ep, NULL, NULL, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_host);
+
+struct mausb_host_ep *mausb_find_ep_by_desc(
+	const struct usb_endpoint_descriptor *ep_desc,
+	struct mausb_dev *mausb_dev)
+
+{
+	return mausb_find_ep(NULL, NULL, NULL, mausb_dev, ep_desc, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_desc);
+
+struct mausb_host_ep *mausb_find_ep_by_handle(struct mausb_ep_handle *handle,
+	struct mausb_dev *mausb_dev)
+{
+	return mausb_find_ep(NULL, NULL, handle, mausb_dev, NULL, 0);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_handle);
+
+struct mausb_host_ep *mausb_find_ep_by_address(u8 address,
+	struct mausb_dev *mausb_dev)
+
+{
+	return mausb_find_ep(NULL, NULL, NULL, mausb_dev, NULL, address);
+}
+EXPORT_SYMBOL(mausb_find_ep_by_address);
+
+struct mausb_host_ep *mausb_find_ep_from_handle(struct mausb_ep_handle handle,
+	struct ma_dev *ma_dev)
+{
+	struct mausb_host_ep *ma_ep;
+	struct mausb_dev *mausb_dev;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry(mausb_dev, &ma_dev->dev_list, dev_list) {
+		spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+		ma_ep = mausb_find_ep_by_handle(&handle, mausb_dev);
+		if (ma_ep != NULL)
+			return ma_ep;
+
+		spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	}
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	return NULL;
+}
+
+/**
+ * Wrapper function to be used by devices when they want to generate an
+ * ma packet.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ma_dev(struct ms_pkt *ms_pkt,
+	struct ma_dev *ma_dev, gfp_t mem_flags)
+{
+	return mausb_pkt_from_ms_pkt(ms_pkt,
+			ma_dev->ms_driver->ops->pkt_destructor, mem_flags);
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt_ma_dev);
+
+/**
+ * Wrapper to be used by endpoints when they want to generate an ma packet.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ep(struct ms_pkt *ms_pkt,
+	struct mausb_host_ep *ep, gfp_t mem_flags)
+{
+	return mausb_pkt_from_ms_pkt_ma_dev(ms_pkt, ep->mausb_dev->ma_dev,
+		mem_flags);
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt_ep);
+
+const struct usb_endpoint_descriptor *mausb_get_ep_des(
+		struct mausb_host_ep *ma_ep)
+{
+	if ((NULL != ma_ep->ep && NULL != ma_ep->dev_ep) ||
+	    (NULL == ma_ep->ep && NULL == ma_ep->dev_ep)) {
+
+		mamem_err("%s: ERROR: ep = 0x%p, dev_ep = 0x%p "
+			"(only one should be set)\n", __func__,
+			ma_ep->ep, ma_ep->dev_ep);
+
+		return NULL;
+	}
+
+	if (NULL != ma_ep->ep)
+		return &ma_ep->ep->desc;
+
+	if (NULL != ma_ep->dev_ep)
+		return ma_ep->dev_ep->desc;
+
+	/* We should never get here */
+	BUG();
+	return NULL;
+}
+EXPORT_SYMBOL(mausb_get_ep_des);
+
+/**
+ * Fills an MA USB packet header for the given maurb
+ */
+static int fill_mausb_dph(struct mausb_dph *ma_pkt, struct mausb_urb *maurb,
+		  bool in, bool host)
+{
+	const struct usb_endpoint_descriptor *ep_des;
+	unsigned long irq_flags;
+
+	/* set the version number */
+	ma_pkt->common.ver_flags =  MAUSB_VERSION_1_0 & MAUSB_VERSION_MASK;
+
+	/* set the host flag if from the host */
+	ma_pkt->common.ver_flags |= host ? MAUSB_PKT_FLAG_HOST : 0;
+
+	/* set the device handle field */
+	spin_lock_irqsave(&maurb->ep->ep_lock, irq_flags);
+	ma_pkt->common.ep_handle = maurb->ep->ep_handle;
+	spin_unlock_irqrestore(&maurb->ep->ep_lock, irq_flags);
+
+	ma_pkt->common.pkt_status = SUCCESS;
+
+	ep_des = mausb_get_ep_des(maurb->ep);
+
+	/* set transfer type in tflags field */
+	switch (usb_endpoint_type(ep_des)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_CTRL;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_ISOC;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_BULK;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ma_pkt->eps_tflags |= MAUSB_PKT_TFLAG_TYPE_INT;
+		break;
+	default:
+		mamem_err("%s: invalid transfer type\n", __func__);
+	}
+
+	return 0;
+}
+
+/**
+ * Create a datapacket from a given URB.
+ */
+struct mausb_pkt *mausb_create_dp(int *status, struct mausb_urb *maurb,
+	bool in, bool host, gfp_t memflags)
+{
+	struct mausb_pkt	*pkt;
+	int			ret = 0;
+
+	pkt = mausb_alloc_pkt(MAUSB_PKT_TYPE_DATA, status, memflags);
+	if (NULL == pkt) {
+		mamem_err("%s:failed to allocate memory for mausb packet\n",
+			__func__);
+
+		if (NULL != status)
+			*status = -ENOMEM;
+
+		return NULL;
+	}
+
+	ret = fill_mausb_dph(pkt->data, maurb, in, host);
+	INIT_LIST_HEAD(&pkt->pkt_list);
+	if (NULL != status)
+		*status = ret;
+
+	return pkt;
+}
+EXPORT_SYMBOL(mausb_create_dp);
+
+struct mausb_urb *mausb_alloc_maurb(struct mausb_host_ep *ma_ep, gfp_t memflags)
+{
+	struct mausb_urb     *maurb;
+
+	maurb = kzalloc(sizeof(struct mausb_urb), memflags);
+	if (!maurb)
+		return NULL;
+
+	INIT_LIST_HEAD(&maurb->urb_list);
+	maurb->ep = ma_ep;
+	maurb->dev = ma_ep->mausb_dev;
+
+	return maurb;
+}
+EXPORT_SYMBOL(mausb_alloc_maurb);
+
+/**
+ * Deletes the given maurb and removes all pointers to it from memory.
+ */
+int mausb_internal_drop_maurb(struct mausb_urb *maurb, struct mausb_hcd *mhcd)
+{
+	struct mausb_host_ep *ep = maurb->ep;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	list_del(&maurb->urb_list);
+	if (maurb == ep->active_transfer)
+		ep->active_transfer = NULL;
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	spin_lock_irqsave(&mhcd->urb_list_lock, irq_flags);
+	list_del(&maurb->ma_hcd_urb_list);
+	spin_unlock_irqrestore(&mhcd->urb_list_lock, irq_flags);
+
+	/*
+	 * Nobody else should know this maurb exists, so it should be
+	 * safe to free
+	 */
+	kfree(maurb);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_drop_maurb);
+
+/**
+ * Sets endpoint state to default.
+ *
+ * @state:	State of endpoint to be configured.
+ * @buf_size:	The maximum number of Bytes the device-side buffer
+ *              can receive from the host.
+ *
+ * Called whenever an MA USB endpoint is configured and needs to be set
+ * or reset to its initial state.
+ */
+void init_ep_state(struct mausb_ep_state *state, u32 buf_size)
+{
+	state->request_id = 0;
+	state->active_request_id = 0;
+	state->seq_number = 0;
+	state->tx_pending = 0;
+	state->earliest_request_id = 0;
+	state->earliest_unacked = 0;
+	state->occupancy = 0;
+	state->rx_buf_size = buf_size;
+	state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+	state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	/* TODO: number of retries depends on transfer type, include
+	 * other transfer types (control and interrupt) */
+}
+
+struct mausb_gadget_ep *usb_ep_to_mausb_gadget_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct mausb_gadget_ep, dev_ep);
+}
+EXPORT_SYMBOL(usb_ep_to_mausb_gadget_ep);
+
+/**
+ * Links a Device-side endpoint to an MA USB endpoint
+ */
+void mausb_link_ma_ep_to_usb_ep(struct mausb_host_ep *ma_ep,
+		struct usb_ep *dev_ep)
+{
+	struct mausb_gadget_ep *gadget_ep = usb_ep_to_mausb_gadget_ep(dev_ep);
+
+	ma_ep->dev_ep = dev_ep;
+	ma_ep->halted = 0;
+	ma_ep->wedged = 0;
+
+	ma_ep->usb_req_list = &gadget_ep->usb_req_list;
+}
+EXPORT_SYMBOL(mausb_link_ma_ep_to_usb_ep);
+
+/*
+ * Adds an endpoint to the specified device.
+ *
+ * @ma_dev:		The usb device to add the endpoint to.
+ * @ep/dev_ep:		The usb struct for the endpoint being added.
+ *			Note: give only one of the endpoint pointers and
+ *                      set the other to NULL.
+ * @mausb_ep:		The mausb_ep struct created by this function.
+ * @transfer_timeout:	The transfer timeout function. A thread will be
+ *                      spawned with this function for handling timeouts.
+ *
+ * Adds the given endpoint to the given device. The difference between this
+ * function and mausb_add_endpoint (which can be called from the usb core)
+ * is that this uses the private ma-structs. Calling this function is
+ * cheaper, and therefore preferred when possible, since mausb_add_endpoint
+ * will have to find the internal structures.
+ */
+int mausb_internal_add_ep(struct mausb_dev *ma_dev,
+		struct usb_host_endpoint *ep, struct usb_ep *dev_ep,
+		struct mausb_host_ep **mausb_ep,
+		int (*transfer_timeout)(void *data), gfp_t memflags)
+{
+	struct mausb_host_ep *ma_ep;
+	unsigned long irq_flags;
+
+	ma_ep = kzalloc(sizeof(struct mausb_host_ep), memflags);
+	if (!ma_ep)
+		return -ENOMEM;
+
+	/* host operations */
+	if (ep != NULL) {
+		ep->hcpriv = ma_ep;
+		ma_ep->ep = ep;
+
+	/* device operations */
+	} else if (dev_ep != NULL)
+		mausb_link_ma_ep_to_usb_ep(ma_ep, dev_ep);
+
+	ma_ep->mausb_dev = ma_dev;
+
+	/* set initial EP State */
+	init_ep_state(&ma_ep->state, DEVICE_RX_BUF_SIZE);
+
+	/*
+	 * only used by full speed devices to determine if the max packet
+	 * size has changed for EP0
+	 */
+	ma_ep->max_pkt = 8;
+
+	/* initialize mausb_ep_handle */
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_UNASSIGNED;
+
+	INIT_LIST_HEAD(&ma_ep->urb_list);
+	INIT_LIST_HEAD(&ma_ep->ep_list);
+	INIT_LIST_HEAD(&ma_ep->req_list);
+	INIT_LIST_HEAD(&ma_ep->resp_list);
+
+	spin_lock_init(&ma_ep->ep_lock);
+	ma_ep->tx_timed_out = false;
+
+	/* initialize endpoint work queue */
+	init_waitqueue_head(&ma_ep->host_ep_wq);
+
+	/* initialize endpoint timer */
+	setup_timer(&ma_ep->timer, wake_timeout_thread, (unsigned long) ma_ep);
+
+	/* add the endpoint to the device */
+	spin_lock_irqsave(&ma_dev->dev_lock, irq_flags);
+	list_add_tail(&ma_ep->ep_list, &ma_dev->ep_list);
+	spin_unlock_irqrestore(&ma_dev->dev_lock, irq_flags);
+
+	/* give a pointer to the ma_ep back to the caller */
+	if (NULL != mausb_ep)
+		*mausb_ep = ma_ep;
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_add_ep);
+
+/**
+ * Drops the given endpoint from the given device. The difference between this
+ * function and mausb_drop_endpoint (which can be called from the usb core)
+ * is that this uses the private ma-structs. Calling this function is
+ * cheaper, and therefore preferred when possible, since mausb_drop_endpoint
+ * will have to find the internal endpoint structure.
+ */
+int mausb_internal_drop_ep(struct mausb_host_ep *ma_ep)
+{
+	struct mausb_dev *ma_dev;
+	struct mausb_request  *ma_request, *next_request;
+	struct mausb_pkt *ma_pkt, *next_pkt;
+	unsigned long     irq_flags;
+	unsigned long     irq_flags2;
+
+	if (NULL == ma_ep)
+		return -EINVAL;
+
+	/* drop all pending transfers */
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+	ma_dev = ma_ep->mausb_dev;
+
+	/* stop transfer timeout thread */
+	if (NULL != ma_ep->timeout_task)
+		kthread_stop(ma_ep->timeout_task);
+
+	/* drop all pending usb_requests (if there are any) */
+	if (NULL != ma_ep->usb_req_list) {
+		list_for_each_entry_safe(ma_request, next_request,
+					ma_ep->usb_req_list, usb_req_list) {
+			list_del(&ma_request->usb_req_list);
+			ma_request->req.status = -ESHUTDOWN;
+			ma_request->req.complete(ma_ep->dev_ep,
+							&ma_request->req);
+		}
+	}
+
+	/* flush out all of the stored request/response packets */
+	list_for_each_entry_safe(ma_pkt, next_pkt, &ma_ep->req_list, pkt_list) {
+		list_del(&ma_pkt->pkt_list);
+		mausb_free_pkt(ma_pkt);
+	}
+	list_for_each_entry_safe(ma_pkt, next_pkt,
+					&ma_ep->resp_list, pkt_list) {
+		list_del(&ma_pkt->pkt_list);
+		mausb_free_pkt(ma_pkt);
+	}
+
+	/* remove the endpoint from the list */
+	spin_lock_irqsave(&ma_dev->dev_lock, irq_flags2);
+	list_del(&ma_ep->ep_list);
+	spin_unlock_irqrestore(&ma_dev->dev_lock, irq_flags2);
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	kfree(ma_ep);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_internal_drop_ep);
+
+/**
+ * Updates the state of an endpoint based on the mausb_ep_des.
+ */
+int mausb_update_ep(struct mausb_host_ep *ma_ep,
+			struct mausb_ep_des *ma_ep_des)
+{
+	unsigned long     irq_flags;
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	if (!ma_ep_des->valid) { /* Valid bit: 0 means valid */
+		ma_ep->ep_handle.handle = ma_ep_des->ep_handle.handle;
+		ma_ep->ep_handle_state = MAUSB_EP_HANDLE_ACTIVE;
+	}
+
+	if (ma_ep_des->dir == 0) {
+		ma_ep->state.rx_buf_size = ma_ep_des->buffer_size;
+
+
+		if (ma_ep_des->l_man)
+			ma_ep->lman_support = true;
+		else
+			ma_ep->lman_support = false;
+	}
+
+	/*TODO: parse and use the remainder of the values in the packet */
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Allocates private per-usb-device data.
+ *
+ * @ma_dev:	The MA USB device to which the USB device belongs
+ * @usb_dev:	The host-side USB device struct to add.
+ * @gadget:	The device-side USB device struct to add.
+ *
+ * This function allocates a new device and adds it onto the MA USB device's
+ * linked list of usb devices. It also allocates endpoint data for the control
+ * endpoint (EP0).
+ */
+struct mausb_dev *mausb_internal_alloc_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, struct usb_gadget *gadget)
+{
+	unsigned long     irq_flags;
+	struct mausb_dev *mausb_dev;
+
+	mausb_dev = kzalloc(sizeof(struct mausb_dev), GFP_KERNEL);
+
+	if (!mausb_dev)
+		return NULL;
+
+	if (NULL != dev)
+		mausb_dev->dev = dev;
+	if (NULL != gadget)
+		mausb_dev->gadget = gadget;
+	mausb_dev->ma_dev = ma_dev;
+	INIT_LIST_HEAD(&mausb_dev->ep_list);
+	INIT_LIST_HEAD(&mausb_dev->dev_list);
+	spin_lock_init(&mausb_dev->dev_lock);
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+
+	/*
+	 * If this is the first device to be allocated, then it should be the
+	 * most upstream.
+	 */
+	if (NULL == ma_dev->top_dev)
+		ma_dev->top_dev = mausb_dev;
+
+	list_add_tail(&mausb_dev->dev_list, &ma_dev->dev_list);
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	return mausb_dev;
+}
+EXPORT_SYMBOL(mausb_internal_alloc_dev);
+
+/**
+ * Frees private per-device data.
+ *
+ * @ma_dev:	The MA USB device that the USB device beingfreed belongs to.
+ * @mausb_dev:	The MA USB data associated with the USB device being freed.
+ *
+ * This function removes a USB device from the MA USB hcd's linked list
+ * and releases the device's media agnostic data structure. All endpoints
+ * belonging to this device are also removed from the MA USB hcd and released
+ * (including EP0).
+ */
+int mausb_internal_free_dev(struct ma_dev *ma_dev, struct mausb_dev *mausb_dev)
+{
+	int			ret = 0;
+	unsigned long		irq_flags, irq_flags2;
+	struct mausb_host_ep	*ma_ep, *next;
+
+	/* remove all the endpoints from the device */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry_safe(ma_ep, next, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		ret = mausb_internal_drop_ep(ma_ep);
+
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	if (!list_empty(&mausb_dev->ep_list)) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		return ret;
+	}
+
+	/* remove the mausb device from the ma device */
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags2);
+	list_del(&mausb_dev->dev_list);
+
+	/* if the top device is being removed */
+	if (ma_dev->top_dev == mausb_dev)
+		ma_dev->top_dev = NULL;
+
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags2);
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	kfree(mausb_dev);
+
+	return ret;
+
+}
+EXPORT_SYMBOL(mausb_internal_free_dev);
+
+/**
+ * Resets all the data in a ma_dev struct. This includes freeing all the MA
+ * data for the usb devices and endpoints connected to this device.
+ */
+int mausb_internal_reset_ma_dev(struct ma_dev *ma_dev, __u8 ma_dev_addr,
+	__u8 mass_id, struct mausb_hcd *mhcd, struct mausb_udc *maudc)
+{
+	int			ret = -EINVAL;
+	struct mausb_dev	*mausb_dev, *mausb_next;
+	int (*req_switch)(struct mausb_mgmt_pkt *req,
+			  struct mausb_mgmt_pkt *resp,
+			  struct mausb_mgmt *mgmt)
+		= ma_dev->mgmt.req_switch;
+	int (*device_connect)(int) = ma_dev->ma_drv.device_connect;
+	unsigned long irq_flags;
+
+	if (NULL != mhcd)
+		ma_dev->mhcd = mhcd;
+
+	if (NULL != maudc)
+		ma_dev->maudc = maudc;
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	list_for_each_entry_safe(mausb_dev, mausb_next, &ma_dev->dev_list,
+				dev_list) {
+		spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+		ret = mausb_internal_free_dev(ma_dev, mausb_dev);
+
+		spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	}
+
+	if (!list_empty(&ma_dev->dev_list)) {
+		/* could not clear all the devices */
+		ret = -EAGAIN;
+	}
+
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+
+	/* TODO: make sure this doesn't break any locking rules */
+	mausb_init_ma_device(ma_dev, ma_dev_addr, mass_id, mhcd,
+			     maudc, req_switch, device_connect);
+
+	return ret;
+}
+
+/**
+ * Initializes the media agnostic management structure.
+ */
+int mausb_init_mgmt(struct mausb_mgmt *mgmt, spinlock_t *ma_dev_lock,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt))
+{
+	INIT_LIST_HEAD(&mgmt->req_list);
+	mgmt->token = 0;
+	mgmt->tx_pair.to_ms.context = NULL;
+	mgmt->tx_pair.to_ms.transfer_packet = NULL;
+	mgmt->tx_pair.to_ma.context = NULL;
+	mgmt->tx_pair.to_ma.transfer_packet = NULL;
+	mgmt->hub_dev_handle = 0;
+	mgmt->ma_dev_lock = ma_dev_lock;
+	mgmt->req_switch = req_switch;
+
+	return 0;
+}
+
+static void mausb_init_pkt_dmux(struct mausb_pkt_transfer *pkt_dmux,
+		void *context)
+{
+	pkt_dmux->transfer_packet = &mausb_pkt_dmux;
+	pkt_dmux->context = context;
+}
+
+/*
+ * Initializes the data structure for an MA USB device.
+ */
+int mausb_init_ma_device(struct ma_dev *ma_dev, __u8 ma_dev_addr, __u8 mass_id,
+		struct mausb_hcd *mhcd, struct mausb_udc *maudc,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt),
+		int (*device_connect)(int))
+{
+	INIT_LIST_HEAD(&ma_dev->dev_list);
+	ma_dev->top_dev = NULL;
+	ma_dev->ma_dev_addr = ma_dev_addr;
+	ma_dev->mass_id = mass_id;
+	if (mhcd != NULL)
+		ma_dev->mhcd = mhcd;
+	if (maudc != NULL)
+		ma_dev->maudc = maudc;
+	spin_lock_init(&ma_dev->ma_dev_lock);
+	ma_dev->ma_drv.device_connect = device_connect;
+	mausb_init_pkt_dmux(&ma_dev->ma_drv.pkt_dmux, ma_dev);
+
+	mausb_init_mgmt(&ma_dev->mgmt, &ma_dev->ma_dev_lock, req_switch);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_init_ma_device);
+
diff --git a/drivers/staging/mausb/drivers/mausb_mem.h b/drivers/staging/mausb/drivers/mausb_mem.h
new file mode 100644
index 0000000..870591f
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mem.h
@@ -0,0 +1,509 @@
+/* Name:	mausb_mem.h
+ * Description: Header for mausb_mem.c. Needed do make calls to
+ *              functions defined in mausb_mem.c.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MEM_H
+#define __MAUSB_MEM_H
+
+#include "mausb_state.h"
+#include "mausb_pkt.h"
+#include "mausb_msapi.h"
+
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/gadget.h>
+#include <linux/timer.h>
+
+#ifdef DEBUG
+#define mamem_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mamem_dbg(format, arg...)
+#endif
+
+#define mamem_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mamem_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* forward declarations */
+struct mausb_urb;
+struct mausb_pkt;
+struct mausb_host_ep;
+
+/**
+ * mausb_mgmt - MAUSB management datastrucure
+ *
+ * Contains all the data necessary to handle management packets.
+ *
+ * @req_list:		List of all currently pending management requests for
+ *			this device.
+ * @token:		The value of the token field in the most recently sent
+ *			management request.
+ * @tx_pair:		Indicates where management packets should be sent.
+ *
+ * The following variables are to store common management packet fields:
+ *
+ * @hub_dev_handle:	Device Handle of the MAUSB Dock hub. used for
+ *                  	USBDevHandleReq packets.
+ * @ma_dev_lock:	The spinlock which protects the management data in this
+ *			struct.
+ * @req_switch:		The host or devices request switch. It accepts an
+ * 			incoming request, makes the necessary calls, and
+ *			returns a partially completed response (it fills the
+ *			response type, status & any data fields specific to
+ *			that response). the remainder of the fields are
+ *			completed by mausb_rx_mgmt_req.
+ */
+struct mausb_mgmt {
+	struct list_head		req_list;
+	__u16				token:10;
+	struct mausb_transfer_pair	tx_pair;
+	__u16				hub_dev_handle;
+	spinlock_t			*ma_dev_lock;
+	int (*req_switch)(struct mausb_mgmt_pkt *req,
+			struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt);
+};
+
+/**
+ * mausb_mgmt_req_list - MAUSB management request list entry
+ *
+ * An entry in the mausb_mgmt request linked list.
+ *
+ * @req_list:	Pointers to other entries in the list.
+ * @mgmt_req:	The request management packet.
+ * @mgmt_resp:	The response management packet, set to NULL until a response
+ *		is received.
+ * @resp_rcvd:	An event triggered when the response is received.
+ */
+struct mausb_mgmt_req_list {
+	struct list_head	req_list;
+
+	struct mausb_pkt	*mgmt_req;
+	struct mausb_pkt	*mgmt_resp;
+
+	struct completion	resp_rcvd;
+};
+
+/**
+ * Media Agnostic Session State
+ *
+ * Defines the current state of the session between the host & device.
+ * Per MAUSB spec, sections 7.1 & 8.1.1.
+ */
+enum mausb_session_state {
+	MAUSB_SESSION_DOWN,
+	MAUSB_SESSION_CONNECTING,
+	MAUSB_SESSION_ACITVE,
+	MAUSB_SESSION_INACTIVE
+};
+
+/**
+ * stores information returned in a CapResp packet
+ */
+struct ma_capability {
+	__u16		num_ep;
+	__u8		num_dev;
+	__u8		num_stream:5;
+	__u8		dev_type:3;
+	__u16		max_tx_reqs;
+	__u16		max_mgmt_reqs:12;
+};
+
+/**
+ * MA device data
+ *
+ * This structure is used to hold MA device-specific data
+ * (i.e. one instance of this structure exists per MA device).
+ *
+ * @mgmt:		Contains the data needed to keep track of the device's
+ *			management packets.
+ * @dev_list:		Stores a list of the devices connected to this HCD.
+ *			This includes any internal mausb data that exists on
+ *			a per-device, per-endpoint, or per-transfer basis.
+ * @top_dev:		The most upstream mausb device. Used to determine
+ *			where to send MA USB device management packets (such as
+ *			MAUSBDevSleepReq and MAUSBDevWakeReq).
+ * @session_state:	Defines the current state of the session between the
+ *			host and device. Per MAUSB spec, sections 7.1 & 8.1.1.
+ * @ma_dev_addr: 	MA Device Address. Assigned by the host via a
+ *               	MAUSBDevResetReq.
+ * @mass_id:		Media-Agnostic Service Set Identifier. Assigned by the
+ *			host via a MAUSBDevResetReq.
+ * @ma_dev_lock:	Spinlock for this device. This lock should be held
+ *			before accessing any data in this structure.
+ * @ma_drv:		Media agnostic driver interfaces.
+ * @ms_drv:		Media specific driver interfaces.
+ * @ma_cap:		Stores MA device info from CapResp packet fields.
+ * @speed:		Stores MA device info from speed capability descriptor.
+ * @pout:		Stores MA device info from P-managed OUT capability
+ *			descriptor.
+ * @iso:		Stores MA device info from isochronous capabilities
+ *			descriptor.
+ * @synch:		Stores MA device info from synchronization capabilities
+ *			descriptor.
+ * @cont_id:		Stores MA device info from container ID capability
+ *			descriptor.
+ * @link_sleep:		Stores MA device info from link sleep capability
+ *			descriptor.
+ */
+struct ma_dev {
+	struct mausb_mgmt		mgmt;
+	struct list_head		dev_list;
+	struct mausb_dev		*top_dev;
+	enum mausb_session_state	session_state;
+	__u8				ma_dev_addr:7;
+	__u8				mass_id;
+	spinlock_t			ma_dev_lock;
+
+	union {
+		struct mausb_hcd *mhcd;
+		struct mausb_udc *maudc;
+	};
+
+	struct mausb_ma_drv		ma_drv;
+	struct mausb_ms_drv		*ms_driver;
+
+	struct ma_capability		ma_cap;
+	struct mausb_dev_cap_speed	*speed;
+	struct mausb_dev_cap_pout	*pout;
+	struct mausb_dev_cap_iso	*iso;
+	struct mausb_dev_cap_sync	*sync;
+	struct mausb_dev_cap_cont_id	*cont_id;
+	struct mausb_dev_cap_link_sleep *link_sleep;
+};
+
+/**
+ * MA USB device data
+ *
+ * This structure is used to hold device-pecific data
+ * (i.e. one instance of this structure exists per usb device).
+ *
+ * @dev:		A pointer to the kernel's usb device structure. Can be
+ *			used to uniquely identify a device.
+ * @gadget:		A pointer to the kernel's usb gadget structure.
+ * @ma_dev:		Pointer to parent ma_dev structure.
+ * @ep_list:		A linked list of all the endpoints for this device.
+ *              	MAUSBDevHandleResp packet.
+ * @dev_handle:		MA USB device handle for this device
+ * @dev_address:	The usb device address. set by the ma_dev.
+ *               	NOTE: this is not the same as the address given by
+ *			the kernel.
+ * @dev_list:		A linked list of all the devices in the HCD.
+ * @dev_lock:		Spinlock for this device. This lock should be held
+ * 			before accessing any data in this structure.
+ */
+struct mausb_dev {
+	union {
+		struct usb_device *dev;	   /* Host only */
+		struct usb_gadget *gadget; /* Device only */
+	};
+	struct ma_dev     *ma_dev;
+	struct list_head   ep_list;
+	__u16              dev_handle;
+	__u8               dev_address;
+	struct list_head   dev_list;
+	spinlock_t         dev_lock;
+};
+
+/**
+ * MAUSB Endpoint Handle State Variables
+ *
+ * Defines the states for an MA USB Endpoint Handle.
+ *
+ * Per MAUSB spec, seciton 7.2
+ *
+ * Note: MAUSB_EP_HANDLE_DELETED is used to flag an endpoint for deletion
+ *       it is not per spec; endpoints in this state should not be used and
+ *       will be deleted in the next EPHandleDeleteReq.
+ */
+enum mausb_ep_handle_state {
+	MAUSB_EP_HANDLE_UNASSIGNED = 0,
+	MAUSB_EP_HANDLE_ACTIVE,
+	MAUSB_EP_HANDLE_INACTIVE,
+	MAUSB_EP_HANDLE_HALTED,
+	MAUSB_EP_HANDLE_DELETED
+};
+
+/**
+ * MA USB host-side endpoint data
+ *
+ * This structure is used to hold endpoint-specific data
+ * (i.e. one instance of this structure exists per endpoint).
+ *
+ * The following data is protected by the devices's dev_lock:
+ *
+ * @ep: 	Used only by the host side. A pointer to the kernel's host-side
+ *      	endpoint structure. Can be used to uniquely identify an
+ *		endpoint. Note: the HCD probably shouldn't read or write
+ *		anything from the usb_host_endpoint structure, since it belongs
+ *		to the kernel.
+ * @dev_ep:	Used only by the device side. A pointer to the kernel's
+ *          	device-side endpoint structure.
+ * @ep_list:	A linked list of all the endpoints connected to the same
+ *           	device.
+ *
+ * The following data is protected by the endpoint's ep_lock:
+ *
+ * @state:		The MA USB state variables for this endpoint. Per
+ *			MA USB Spec, sections 5.4.1 and 5.5.2.
+ * @active_transfer:	Urb that maps to the transfer in progress.
+ * @ep_handle:		The endpoint handle to be used by packets for this
+ *			endpoint per MA USB Spec, section 6.2.1.5.
+ * @ep_handle_state:	Defines the states an Endpoint Handle can be in.
+ *                   	Per MA USB Spec, section 7.2.
+ * @buffer:		Buffer that holds data going to/from a host during
+ *			transfer.
+ * @actual_length:	Length of buffer.
+ * @lman_support:	For control or non-iso OUT endpoints. Indicates if
+ *                	link-managed tranfers are supported. Not valid until
+ *                	an EPHandleResp is received for this endpoint.
+ * @control_dir:	Control endpoints only; used to determine the direction
+ *               	of the current transfer.
+ * @ccu:		The credit conumption unit, in bytes. Per MA USB Spec,
+ *			table 27.
+ * @mausb_dev:		The device the endpoint belongs to.
+ * @urb_list:		A linked list of all URBs pending for this endpoint.
+ *            		URBs map one-to-one with MAUSB Transfers, so each entry
+ *            		also represents an MA USB Transfer.
+ * @usb_req_list:	Only used on the device side. A linked list of all
+ *                	usb_requests submitted to this endpoint.
+ * @req_list:		Head of list of created transferRequests and
+ *	      		transferAck packets.
+ * @resp_list:		Head of list of received transferResponses packets.
+ * @ep_lock:		Spinlock for this endpoint. This lock should be held
+ *			before accessing any data in this structure.
+ * @timer:		Endpoint timer structure, used to monitor transfer
+ *			timeouts.
+ * @timeout_task:	Thread used to perform packet resends after transfer
+ *			timeout.
+ * @host_ep_wq:		Work queue for timeout thread to wait on while sleeping.
+ * @tx_timed_out:	Used to flag when a timeout event has occured during
+ *			a transfer.
+ * @tx_pair:		Transfer pair for this endpoint.
+ * @gadget:		USB gadget associated with this endpoint.
+ * @busy:		True if this endpoint is busy, otherwise false.
+ * @halted:		1 if endpoint is halted, otherwise 0.
+ * @wedged:		1 if endpoint is wedged, otherwise 0.
+ * @stream_en:		1 if streams are enabled for this endpoint, otherwise 0.
+ * @max_pkt:		Max packet size for this endpoint.
+ */
+struct mausb_host_ep {
+
+	struct usb_host_endpoint	*ep; 	 /* Host only */
+	struct usb_ep			*dev_ep; /* Device only */
+	struct list_head		ep_list;
+	struct mausb_ep_state		state;
+	struct mausb_urb		*active_transfer;
+	struct mausb_ep_handle		ep_handle;
+	enum mausb_ep_handle_state	ep_handle_state;
+	void				*buffer;
+	u32				actual_length;
+	bool				lman_support;
+	bool				control_dir;
+	u16				ccu;
+	struct mausb_dev		*mausb_dev;
+	struct list_head		urb_list;
+	struct list_head		*usb_req_list;
+	struct list_head		req_list;
+	struct list_head		resp_list;
+	spinlock_t			ep_lock;
+	struct timer_list		timer;
+	struct task_struct		*timeout_task;
+	wait_queue_head_t		host_ep_wq;
+	bool				tx_timed_out;
+	struct mausb_transfer_pair	tx_pair;
+	struct usb_gadget		*gadget; /* Device only */
+	bool				busy;
+	unsigned			halted:1;
+	unsigned			wedged:1;
+	unsigned			stream_en:1;
+	u16                             max_pkt;
+};
+
+/**
+ * endpoint request structure - describes one I/O request
+ *
+ * @usb_ep:	A device-side endpoint structure.
+ * @queue:	The list of all requests currently enqueued to this endpoint.
+ */
+struct mausb_gadget_ep {
+	struct usb_ep dev_ep;
+	struct list_head usb_req_list;
+};
+
+/**
+ * MA USB urb structure
+ *
+ * Stores MAUSB-specific urb data. In our implementation, one urb from usb
+ * core maps to exactly one MA USB transfer. When an urb is submitted, it
+ * queues a new transfer. When a transfer is complete (or fails), the urb
+ * is given back to the core.
+ *
+ * All data listed in this structure is protected by the ep_lock.
+ * If you want to use any of this data, you need to be in posession
+ * of this lock.
+ *
+ * @urb:		Used only on the host side. The urb submitted to the
+ *			HCD by usbcore.
+ * @usb_request_list:	Used only on the device side. A pointer to the list of
+ *                    	msusb_requests for this endpoint.
+ * @urb_list:		Connects this mausb_urb with other mausb_urbs
+ *			queued to the same endpoint.
+ * @ma_hcd_urb_list:	Connects this urb to urbs queued to the same ma hcd.
+ * @state:		Current state of the transfer as defined in the
+ *			MA USB Spec.
+ * @ep:			The endpoint that the transfer belongs to.
+ * @dev:		The device that the transfer belongs to.
+ * @transfer_size:	Total number of bytes for transfer associated with urb.
+ */
+struct mausb_urb {
+	struct urb			*urb;		   /* Host Only */
+	struct list_head		*usb_request_list; /* Device Only */
+	struct list_head		urb_list;
+	struct list_head		ma_hcd_urb_list;
+	struct mausb_transfer_state	state;
+	struct mausb_host_ep		*ep;
+	struct mausb_dev		*dev;
+	unsigned int			transfer_size;
+};
+
+/**
+ * endpoint request structure - describes one I/O request
+ *
+ * @req:		The usb_request struct. Enqueuing a usb_request is
+ *			what triggers the creation of this struct.
+ * @usb_req_list:	List of all requests enqueued at this endpoint.
+ */
+struct mausb_request {
+	struct usb_request req;
+	struct list_head   usb_req_list;
+};
+
+/* endpoint/device helper functions */
+struct mausb_host_ep *usb_to_ma_endpoint(struct usb_host_endpoint *ep);
+int mausb_hcd_urb_count(struct mausb_hcd *mhcd);
+
+#define MAUSB_ADD  true
+#define MAUSB_DEL  false
+#define MAUSB_DEV  false
+#define MAUSB_HOST true
+#define MAUSB_OUT  false
+#define MAUSB_IN   true
+struct mausb_pkt *mausb_create_dp(int *status, struct mausb_urb *maurb,
+		bool in, bool host, gfp_t memflags);
+
+/* endpoint/device memory management functions */
+struct mausb_host_ep *mausb_state_to_ep(struct mausb_ep_state *state);
+struct ma_dev *context_to_ma_dev(void *context);
+struct mausb_hcd *mausb_host_ep_to_mahcd(struct mausb_host_ep *ep);
+struct mausb_udc *mausb_host_ep_to_maudc(struct mausb_host_ep *ep);
+struct mausb_dev *usb_dev_to_mausb_dev(struct usb_device *udev);
+struct mausb_host_ep *mausb_find_ep_dev(struct usb_ep *dev_ep,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_host(struct usb_host_endpoint *ep,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_by_handle(struct mausb_ep_handle *handle,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_from_handle(struct mausb_ep_handle handle,
+		struct ma_dev *ma_dev);
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ma_dev(struct ms_pkt *ms_pkt,
+		struct ma_dev *ma_dev, gfp_t mem_flags);
+struct mausb_pkt *mausb_pkt_from_ms_pkt_ep(struct ms_pkt *ms_pkt,
+		struct mausb_host_ep *ep, gfp_t mem_flags);
+struct mausb_dev *mausb_find_dev(struct ma_dev *ma_dev, struct usb_device *dev,
+		unsigned long *handle, struct usb_gadget *gadget);
+struct mausb_dev *mausb_find_dev_host(struct ma_dev *ma_dev,
+		struct usb_device *dev);
+struct mausb_host_ep *mausb_find_ep_by_desc(
+		const struct usb_endpoint_descriptor *ep_desc,
+		struct mausb_dev *mausb_dev);
+struct mausb_host_ep *mausb_find_ep_by_address(u8 address,
+		struct mausb_dev *mausb_dev);
+struct mausb_urb *mausb_alloc_maurb(struct mausb_host_ep *ma_ep,
+		gfp_t memflags);
+int mausb_internal_drop_maurb(struct mausb_urb *maurb, struct mausb_hcd *mhcd);
+void init_ep_state(struct mausb_ep_state *state, u32 buf_size);
+int mausb_activate_endpoints(struct mausb_dev *mausb_dev);
+void mausb_link_ma_ep_to_usb_ep(struct mausb_host_ep *ma_ep,
+		struct usb_ep *dev_ep);
+struct mausb_gadget_ep *usb_ep_to_mausb_gadget_ep(struct usb_ep *ep);
+int mausb_internal_add_ep(struct mausb_dev *ma_dev,
+		struct usb_host_endpoint *ep, struct usb_ep *dev_ep,
+		struct mausb_host_ep **mausb_ep,
+		int (*transfer_timeout)(void *data), gfp_t memflags);
+int mausb_internal_drop_ep(struct mausb_host_ep *ma_ep);
+int mausb_update_ep(struct mausb_host_ep *ma_ep,
+		struct mausb_ep_des *ma_ep_des);
+struct mausb_dev *mausb_internal_alloc_dev(struct ma_dev *ma_dev,
+		struct usb_device *dev, struct usb_gadget *gadget);
+int mausb_internal_free_dev(struct ma_dev *ma_dev,
+		struct mausb_dev *mausb_dev);
+int mausb_internal_reset_ma_dev(struct ma_dev *ma_dev, __u8 ma_dev_addr,
+		__u8 mass_id, struct mausb_hcd *mhcd, struct mausb_udc *maudc);
+int mausb_init_ma_device(struct ma_dev *ma_dev, __u8 ma_dev_addr, __u8 mass_id,
+		struct mausb_hcd *mhcd, struct mausb_udc *maudc,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt),
+		int (*device_connect)(int));
+int mausb_init_mgmt(struct mausb_mgmt *mgmt, spinlock_t *ma_dev_lock,
+		int (*req_switch)(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt));
+const struct usb_endpoint_descriptor *mausb_get_ep_des(
+		struct mausb_host_ep *ma_ep);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_state.h b/drivers/staging/mausb/drivers/mausb_state.h
new file mode 100644
index 0000000..01f0171
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_state.h
@@ -0,0 +1,184 @@
+/* Name:	mausb_state.h
+ * Description: Contains all of the state variables for hosts and devices as
+ *              defined by the MAUSB spec.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_STATE_H
+#define __MAUSB_STATE_H
+
+/**
+ * MAUSB endpoint state variables, per MA USB Spec sections 5.4.1 & 5.5.2.
+ *
+ * Note: this struct contains the fields necessary to store the state on both
+ * the host and device side.
+ *
+ * @seq_number:		For a sender, this field contains the sequence number
+ *			that should be placed in the next outgoing packet.
+ *              	For a receiver, this field contains the sequence number
+ *              	expected in the next incoming packet.
+ * @keep_alive_timer:	Timeout counter. Set to aMausbTransferKeepAlive
+ *                    	upon a new transfer initialization. To be decremented
+ *                    	every aMAUSBTransferTimeTick interval. If the timer
+ *                    	reaches 0, A retry is triggered.
+ * @retry_counter: 	Indicates how many more times the
+ *                 	transfer will be attempted. Decremented upon a timeout
+ *                 	(see keep_alive_timer for details). If this counter
+ *                 	reaches 0, the transfer fails due to a timeout.
+ * @request_id: 	Request ID number. for IN transfers,  all
+ *			transfer_request packets currently being sent or
+ *			received should have this request ID number. for OUT
+ *			transfers, All transfer_request and transfer_ack
+ *			packets currently being sent or received should have
+ *			this request ID number.
+ * @active_request_id: 	Active Request ID number. used by IN transfers only.
+ *                     	All transfer_ack packets being sent/received should
+ *                     	contain this number.
+ * @earliest_unacked: 	Stores the sequence number of the most recent packet
+ *                    	that has been sent out but has not been acknowledged
+ *                    	by the receiver.
+ * @rx_buf_size: 	Receiver Buffer Size. Used for OUT transfers only.
+ *			Indicates the available buffer space for packets in the
+ *			device (in bytes).
+ *			Note: this value is signed for the host and
+ *			unsigned for the receiver. A negative number
+ *			indicates a buffer overflow.
+ *			Note: defined in spec as a 25-bit signed int
+ *			for a host and a 32-bit unsigned for a device.
+ * @occupancy: 		Size (in bytes) of the payload accepted into the receive
+ *             		buffer. Used only on the device side for OUT transfers.
+ * @earliest_request_id:Request ID of earliest transferReq whose state
+ *			needs to be tracked (host IN).
+ * @transfer_retries:	Reload value for retry_counter. Should be set to
+ *		      	a ControlTransferRetries, aBulkTransferRetries,
+ *		      	or aInterruptTransferRetries depending on transfer
+ *		      	type.
+ * @delayed:		Set to true if the interval between two sucessive
+ *			transferResp packets exceeds aTransferRepeatTime.
+ * @tx_pending: 	Set to 1 when a transfer is in progress, otherwise it
+ *			should be zero. A new transfer cannot be started until
+ *			this flag is cleared.
+ */
+struct mausb_ep_state {                      /* HOST     | DEVICE       */
+
+	unsigned int seq_number:24;          /* IN | OUT | IN | OUT     */
+	int 	     keep_alive_timer;       /* IN | OUT | IN | OUT     */
+	unsigned int retry_counter;          /* IN | OUT | IN | OUT     */
+	__u8         request_id;             /* IN | OUT | IN | OUT     */
+	__u8         active_request_id;      /* IN | OUT | IN |         */
+	unsigned int earliest_unacked:24;    /*    | OUT | IN | OUT     */
+	__u32        rx_buf_size;            /*    | OUT |    | OUT     */
+	unsigned int occupancy;              /*    |     |    | OUT     */
+	u8	     earliest_request_id;    /* IN | OUT | IN | OUT     */
+	unsigned int transfer_retries;       /* IN | OUT | IN | OUT     */
+	bool	     delayed;                /*    |     | IN |         */
+
+	/* TODO: add response_timer (device IN and OUT/host OUT) */
+
+	unsigned int tx_pending:1;       /* beyond spec */
+};
+
+/**
+ * MA USB transfer state variables, per section 5.4.1 & 5.5.2.
+ *
+ * In our implementation, URBs and MAUSB transfers map one-to-one,
+ * so the transfer state and the urb state are one in the same.
+ *
+ * @rem_size:		The remaining transfer size (in bytes). This value is
+ *			set at the beginning of a transfer and is decremented
+ *			as data is received.
+ * @payload_size:	Payload size for out transfer (in bytes). For MA USB
+ *			host, it indicates the overall transfered OUT payload
+ *			size for the current urb. For MA USB device, It
+ *			indicates the received OUT payload size for the
+ *			current MA USB OUT request.
+ * @transfer_error:	A boolean which is only set to TRUE when a
+ *			non-recoverable error is detected in the transfer.
+ * @transfer_complete: 	A boolean which is only set to TRUE when a transfer
+ *                     	is evaluated to be complete. (ie. the final ACK has
+ *                     	has been sent/received).
+ * @eot_detected: 	A boolean which is only set to TRUE when a transfer
+ *                	is complete (ie: all the data has been transferred).
+ *                	Note: eot_detected & transfer_complete differ in when
+ *                	they are set. eot_detected is sent after the last data
+ *                	packet received, transfer_complete is set after the
+ *			final ACK.
+ * @last_transfer_sn: 	Last Transfer Sequence Number. Stores the sequence
+ *                    	number of the final packet of this transfer.
+ * @transfer_acked:	Set to true when a transferReq or transferAck packet is
+ *                  	released to the data channel acknowledging the last
+ *		    	transferResp belonging to a transfer.
+ * @k:			A  transfer-dependent multiplicative factor used to
+ *			reload keep_alive_timer when a transfer has a status
+ *			of TRANSFER_PENDING.
+ * @ack_transfer_sn:	The value of the sequence number in the last
+ *                   	transferReq packet that belongs to the transfer and
+ *                   	has the ARQ field set to 1.
+ */
+struct mausb_transfer_state {             /* HOST     | DEVICE       */
+
+	__u32        rem_size;            /* IN | OUT | IN | OUT     */
+	__u32        payload_size;        /* IN | OUT | IN | OUT     */
+	bool         transfer_error;      /* IN | OUT | IN | OUT     */
+	bool         transfer_complete;   /* IN | OUT | IN | OUT     */
+	bool         eot_detected;        /* IN |     | IN | OUT     */
+	unsigned int last_transfer_sn:24; /* IN |     | IN |         */
+	bool         transfer_acked;      /* IN | OUT |    |         */
+	unsigned int k;                   /* IN |     |    |         */
+	unsigned int ack_transfer_sn:24;  /*    | OUT |    |         */
+
+	/*TODO: add transfer_completion_timer (host IN) */
+};
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 04/10] added media agnostic (MA) USB packet handling
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-12 14:01     ` Oliver Neukum
  2014-11-11  2:09   ` [V2 PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
                     ` (7 subsequent siblings)
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we handle MA USB packets. The structure and types of MA USB
packets are defined in the MA USB specification. When an MA USB driver
receives a USB packet, it translates it into a MA USB packet (or packets
if urb exceeds maximum USB packet size). When an MA USB packet is received,
the data from that packet is given to the waiting USB packet and the USB
packet is released.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_pkt.c | 1038 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_pkt.h |  914 +++++++++++++++++++++++++
 2 files changed, 1952 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_pkt.h

diff --git a/drivers/staging/mausb/drivers/mausb_pkt.c b/drivers/staging/mausb/drivers/mausb_pkt.c
new file mode 100644
index 0000000..c78cfc2
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_pkt.c
@@ -0,0 +1,1038 @@
+/* name:	mausb_pkt.c
+ * description: MA USB packet helper functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb.h>
+
+#include "mausb_mem.h"
+#include "mausb_pkt.h"
+#include "mausb_const.h"
+
+/**
+ * Translates numerical packet type into corresponding string (for printing).
+ */
+const char *mausb_type_to_string(enum mausb_pkt_type type)
+{
+	switch (type) {
+	case CapReq:
+		return "CapReq";
+	case CapResp:
+		return "CapResp";
+	case USBDevHandleReq:
+		return "USBDevHandleReq";
+	case USBDevHandleResp:
+		return "USBDevHandleResp";
+	case EPHandleReq:
+		return "EPHandleReq";
+	case EPHandleResp:
+		return "EPHandleResp";
+	case EPActivateReq:
+		return "EPActivateReq";
+	case EPActivateResp:
+		return "EPActivateResp";
+	case EPInactivateReq:
+		return "EPInactivateReq";
+	case EPInactivateResp:
+		return "EPInactivateResp";
+	case EPResetReq:
+		return "EPResetReq";
+	case EPResetResp:
+		return "EPResetResp";
+	case EPClearTransferReq:
+		return "EPClearTransferReq";
+	case EPClearTransferResp:
+		return "EPClearTransferResp";
+	case EPHandleDeleteReq:
+		return "EPHandleDeleteReq";
+	case EPHandleDeleteResp:
+		return "EPHandleDeleteResp";
+	case DevResetReq:
+		return "DevResetReq";
+	case DevResetResp:
+		return "DevResetResp";
+	case ModifyEP0Req:
+		return "ModifyEP0Req";
+	case ModifyEP0Resp:
+		return "ModifyEP0Resp";
+	case SetUSBDevAddrReq:
+		return "SetUSBDevAddrReq";
+	case SetUSBDevAddrResp:
+		return "SetUSBDevAddrResp";
+	case UpdateDevReq:
+		return "UpdateDevReq";
+	case UpdateDevResp:
+		return "UpdateDevResp";
+	case USBDevDisconnectReq:
+		return "USBDevDisconnectReq";
+	case USBDevDisconnectResp:
+		return "USBDevDisconnectResp";
+	case USBSuspendReq:
+		return "USBSuspendReq";
+	case USBSuspendResp:
+		return "USBSuspendResp";
+	case USBResumeReq:
+		return "USBResumeReq";
+	case USBResumeResp:
+		return "USBResumeResp";
+	case RemoteWakeReq:
+		return "RemoteWakeReq";
+	case RemoteWakeResp:
+		return "RemoteWakeResp";
+	case PingReq:
+		return "PingReq";
+	case PingResp:
+		return "PingResp";
+	case DevDisconnectReq:
+		return "DevDisconnectReq";
+	case DevDisconnectResp:
+		return "DevDisconnectResp";
+	case DevInitDisconnectReq:
+		return "DevInitDisconnectReq";
+	case DevInitDisconnectResp:
+		return "DevInitDisconnectResp";
+	case SyncReq:
+		return "SyncReq";
+	case SyncResp:
+		return "SyncResp";
+	case CancelTransferReq:
+		return "CancelTransferReq";
+	case CancelTransferResp:
+		return "CancelTransferResp";
+	case EPOpenStreamReq:
+		return "EPOpenStreamReq";
+	case EPOpenStreamResp:
+		return "EPOpenStreamResp";
+	case EPCloseStreamReq:
+		return "EPCloseStreamReq";
+	case EPCloseStreamResp:
+		return "EPCloseStreamResp";
+	case USBDevResetReq:
+		return "USBDevResetReq";
+	case USBDevResetResp:
+		return "USBDevResetResp";
+	case DevNotificationReq:
+		return "DevNotificationReq";
+	case DevNotificationResp:
+		return "DevNotificationResp";
+	case EPSetKeepAliveReq:
+		return "EPSetKeepAliveReq";
+	case EPSetKeepAliveResp:
+		return "EPSetKeepAliveResp";
+	case GetPortBWReq:
+		return "GetPortBWReq";
+	case GetPortBWResp:
+		return "GetPortBWResp";
+	case SleepReq:
+		return "SleepReq";
+	case SleepResp:
+		return "SleepResp";
+	case WakeReq:
+		return "WakeReq";
+	case WakeResp:
+		return "WakeResp";
+	case VendorSpecificReq:
+		return "VendorSpecificReq";
+	case VendorSpecificResp:
+		return "VendorSpecificResp";
+	case TransferSetupReq:
+		return "TransferSetupReq";
+	case TransferSetupResp:
+		return "TransferSetupResp";
+	case TransferTearDownConf:
+		return "TransferTearDownConf";
+	case TransferReq:
+		return "TransferReq";
+	case TransferResp:
+		return "TransferResp";
+	case TransferAck:
+		return "TransferAck";
+	case IsochTransferReq:
+		return "IsochTransferReq";
+	case IsochTransferResp:
+		return "IsochTransferResp";
+	}
+
+	return "unknown";
+}
+EXPORT_SYMBOL(mausb_type_to_string);
+
+/**
+ * Translates a negative errno to a MAUSB status. Returns a packet status value.
+ */
+enum mausb_pkt_status mausb_errno_to_ma_status(int errno)
+{
+	switch (errno) {
+	case 0: /* no error */
+		return SUCCESS;
+	case -EINPROGRESS:
+		return TRANSFER_PENDING;
+	case -ESTRPIPE:
+		return TRANSFER_EP_STALL;
+	/* TODO: map all relevant ma status' */
+	default:
+		return UNSUCCESSFUL;
+	} /* end switch */
+
+}
+EXPORT_SYMBOL(mausb_errno_to_ma_status);
+
+/**
+ * Translates an URB status to a MAUSB status
+ */
+int mausb_to_urb_status(enum mausb_pkt_status pkt_status)
+{
+	switch (pkt_status) {
+	case SUCCESS: /* no error */
+		return 0;
+	case TRANSFER_PENDING:
+		return -EINPROGRESS;
+	case TRANSFER_EP_STALL:
+		return -ESTRPIPE;
+	/* TODO: map all relevant urb statuses */
+	default:
+		return -EIO; /* generic I/O error */
+	} /* end switch */
+
+}
+EXPORT_SYMBOL(mausb_to_urb_status);
+
+/**
+ * Determines if the packet is a response packet. Returns true if the packet is
+ * a response packet. Returns false otherwise.
+ */
+bool mausb_pkt_resp(struct mausb_pkt *pkt)
+{
+	return pkt->common->pkt_type & MAUSB_PKT_RESP_FLAG;
+}
+
+/**
+ * Determines if a given packet is a management packet.
+ */
+static bool mausb_pkt_is_mgmt(struct mausb_pkt_common *common)
+{
+	if ((common->pkt_type & MAUSB_PKT_TYPE_MASK) == MAUSB_PKT_TYPE_MGMT)
+		return true;
+	else
+		return false;
+}
+
+
+/**
+ * Returns the sum of the sequnce number & the value added. Handles sequence
+ * number wraparound.
+ */
+u32 mausb_seq_num_add(u32 seq_num, int val)
+{
+	return (seq_num + val) % (MAUSB_MAX_SEQ_NUM + 1);
+}
+EXPORT_SYMBOL(mausb_seq_num_add);
+
+/**
+ * Increments a sequence number value by one.
+ */
+void mausb_increment_seq_num(u32 *seq_num)
+{
+	*seq_num = mausb_seq_num_add(*seq_num, 1);
+}
+
+/**
+ * Compares two sequence numbers. Returns true if a is less than b.
+ * Handles sequence number wraparound.
+ */
+bool mausb_seq_num_lt(u32 a, u32 b)
+{
+
+	if (a > MAUSB_MAX_SEQ_NUM || b > MAUSB_MAX_SEQ_NUM) {
+		mapkt_warn("%s: input out of range\n", __func__);
+		return false;
+	}
+
+	if (b < MAUSB_HALF_SEQ_NUM) { /* b is in the lower half */
+
+		if ((b > a) || ((b + MAUSB_HALF_SEQ_NUM) < a))
+			return true;
+		else
+			return false;
+
+	} else { /* b is in the upper half */
+
+		if ((b > a) && (b - MAUSB_HALF_SEQ_NUM) < a)
+			return true;
+		else
+			return false;
+	}
+
+	/* we should never get here */
+	BUG();
+	return false;
+}
+EXPORT_SYMBOL(mausb_seq_num_lt);
+
+/**
+ * Sequence number less than or equal to.
+ */
+bool mausb_seq_num_lt_eq(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(b, a) ? false : true;
+}
+
+/**
+ * Sequence number greater than or equal to.
+ */
+bool mausb_seq_num_gt_eq(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(a, b) ? false : true;
+}
+
+/**
+ * Sequence number greater than.
+ */
+bool mausb_seq_num_gt(u32 a, u32 b)
+{
+	return mausb_seq_num_lt(b, a);
+}
+EXPORT_SYMBOL(mausb_seq_num_gt);
+
+/**
+ * Returns the sum of the request id and the value added. Handles request id
+ * wraparound.
+ */
+u8 mausb_req_id_add(u8 req_id, int val)
+{
+	return (req_id + val) % (MAUSB_MAX_REQ_ID + 1);
+}
+EXPORT_SYMBOL(mausb_req_id_add);
+
+/**
+ * Compares 2 request IDs. Returns true if a is less than b. Handles request id
+ * wraparound.
+ */
+bool mausb_req_id_lt(u8 a, u8 b)
+{
+
+	if (a > MAUSB_MAX_REQ_ID || b > MAUSB_MAX_REQ_ID) {
+		mapkt_warn("%s: input out of range\n", __func__);
+		return false;
+	}
+
+	if (b < MAUSB_HALF_REQ_ID) { /* b is in the lower half */
+
+		if ((b > a) || ((b + MAUSB_HALF_REQ_ID) < a))
+			return true;
+		else
+			return false;
+
+	} else { /* b is in the upper half */
+
+		if ((b > a) && (b - MAUSB_HALF_REQ_ID) < a)
+			return true;
+		else
+			return false;
+	}
+
+	/* we should never get here */
+	BUG();
+	return false;
+}
+EXPORT_SYMBOL(mausb_req_id_lt);
+
+bool mausb_req_id_gt(u8 a, u8 b)
+{
+	return mausb_req_id_lt(b, a);
+}
+
+bool mausb_req_id_gt_eq(u8 a, u8 b)
+{
+	return mausb_req_id_lt(a, b) ? false : true;
+}
+EXPORT_SYMBOL(mausb_req_id_gt_eq);
+
+/**
+ * Finds an endpoint descriptor inside of an endpoint handle request
+ */
+struct usb_endpoint_descriptor *mausb_ep_handle_req_get_ep_des(
+	struct mausb_EPHandleReq_flds *req, int i)
+{
+
+	if (i >= le32_to_cpu(req->num_ep_des)) {
+		mapkt_warn("%s: endpoint descriptor not in packet\n", __func__);
+		return NULL;
+	}
+
+	if (MAUSB_EP_REQ_SIZE == le32_to_cpu(req->size_ep_des)) {
+		return (struct usb_endpoint_descriptor *)
+					&req->ep_des[i].ep_des;
+
+	} else if (MAUSB_SS_EP_REQ_SIZE == le32_to_cpu(req->size_ep_des)) {
+		return (struct usb_endpoint_descriptor *)
+					 &req->ss_ep_des[i].ep_des;
+
+	} else {
+		mapkt_err("%s: unsupported size_ep_des value (%u)\n",
+			  __func__, le32_to_cpu(req->size_ep_des));
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(mausb_ep_handle_req_get_ep_des);
+
+static struct mausb_pkt_common *mausb_header_from_ms_pkt(struct ms_pkt *pkt)
+{
+	struct mausb_pkt_common *header;
+
+	if (pkt->kvec[0].iov_len < sizeof(*header)) {
+		mapkt_err("%s: first entry too small for header\n", __func__);
+		header = NULL;
+	} else
+		header = pkt->kvec[0].iov_base;
+
+	return header;
+}
+
+/**
+ * Accepts an MA USB packet for the MA device and forwards it to the correct
+ * handler based on packet type and endpoint/device handle.
+ */
+int mausb_pkt_dmux(struct ms_pkt *pkt, void *context)
+{
+	int				ret = -EINVAL;
+	struct mausb_pkt_common		*header = mausb_header_from_ms_pkt(pkt);
+	struct ma_dev			*ma_dev = context_to_ma_dev(context);
+	struct mausb_host_ep		*ma_ep = NULL;
+	struct mausb_pkt_transfer	*transfer = NULL;
+
+	if (mausb_pkt_is_mgmt(header)) {
+		transfer = &ma_dev->mgmt.tx_pair.to_ma;
+
+	} else {
+		/* otherwise, find the endpoint it belongs to */
+		ma_ep = mausb_find_ep_from_handle(header->ep_handle,
+			ma_dev);
+
+		if (NULL != ma_ep)
+			transfer = &ma_ep->tx_pair.to_ma;
+	}
+
+	if (NULL != transfer)
+		ret = transfer->transfer_packet(pkt, transfer->context);
+
+	return ret;
+}
+
+/**
+ * Packet destructor for packets generated by the MA driver. For packets that we
+ * have created, we want to free the header but not the data buffers (since the
+ * buffers belong to the URB).
+ */
+static void mausb_pkt_destructor(struct ms_pkt *ms_pkt)
+{
+	struct mausb_pkt *ma_pkt = ms_pkt_to_mausb_pkt(ms_pkt);
+
+	kfree(ma_pkt->common);
+
+	return;
+}
+
+/**
+ * Allocates space for given packet type.
+ */
+struct mausb_pkt *mausb_alloc_pkt(enum mausb_pkt_type pkt_type, int *status,
+		gfp_t memflags)
+{
+	int			size;
+	int			ret = 0;
+	struct mausb_pkt	*pkt;
+
+	/* determine header length */
+	switch (pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	case MAUSB_PKT_TYPE_MGMT:
+		size = sizeof(struct mausb_mgmt_pkt);
+		break;
+	case MAUSB_PKT_TYPE_CTRL:
+		size = sizeof(struct mausb_ctrl_pkt);
+		break;
+	case MAUSB_PKT_TYPE_DATA:
+		size = sizeof(struct mausb_iso_dph);
+		break;
+	default:
+		mapkt_err("%s: could not determine packet type\n", __func__);
+		if (NULL != status)
+			*status = -EINVAL;
+		return NULL;
+	}
+
+	pkt = kzalloc(sizeof(struct mausb_pkt), memflags);
+	if (NULL == pkt) {
+		ret = -ENOMEM;
+		pkt = NULL;
+	} else {
+		pkt->common = kzalloc(size, memflags);
+		if (NULL == pkt->common) {
+			mapkt_err("could not allocate memory for MA USB"
+				" packet header of length %i\n", size);
+			kfree(pkt);
+			ret = -ENOMEM;
+			pkt = NULL;
+		}
+
+		pkt->ms_pkt_destructor = &mausb_pkt_destructor;
+		pkt->orig_pkt = &pkt->pkt;
+	}
+
+	if (NULL != status)
+		*status = ret;
+
+	return pkt;
+}
+
+/**
+ * Deletes the given data packet
+ */
+void mausb_free_pkt(struct mausb_pkt *pkt)
+{
+	/* kill the buffers (when necessary) */
+	pkt->ms_pkt_destructor(pkt->orig_pkt);
+	kfree(pkt);
+}
+EXPORT_SYMBOL(mausb_free_pkt);
+
+/**
+ * Returns the length of the header or a negative errno.
+ */
+int mausb_pkt_header_length(struct mausb_pkt_common *header)
+{
+	int length;
+
+	switch (header->pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	case MAUSB_PKT_TYPE_MGMT:
+	case MAUSB_PKT_TYPE_CTRL:
+		length = le16_to_cpu(header->length);
+		break;
+	case MAUSB_PKT_TYPE_DATA:
+		length = sizeof(struct mausb_dph);
+		break;
+	default:
+		mapkt_err("%s:invalid packet type\n", __func__);
+		length = -EINVAL;
+		break;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(mausb_pkt_header_length);
+
+/**
+ * Returns a pointer to a buffer of specified length that is
+ * found offset a given number of bytes into the ms_pkt.
+ *
+ * If a contigious buffer can be found, this function returns
+ * the virtual address of this buffer. otherwise, it returns null
+ */
+static void *mausb_get_buf_from_ms_pkt(struct ms_pkt *pkt,
+		int offset, int buf_length)
+{
+	int		i;
+	int		page_offset = offset;
+	char		*ret = NULL;
+	struct kvec	*current_kvec;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_kvec = &pkt->kvec[i];
+
+		/* if the buffer is in this kvec entry */
+		if (page_offset < current_kvec->iov_len) {
+
+			/* and the whole buffer is in current_kvec */
+			if (page_offset + buf_length <= current_kvec->iov_len) {
+				ret = (char *) current_kvec->iov_base;
+				ret += page_offset;
+			}
+
+			return ret;
+		}
+
+		page_offset -= current_kvec->iov_len;
+	}
+
+	if (0 != page_offset) {
+		mapkt_err("%s: offset of %i Bytes is greater than packet"
+			" length\n", __func__, page_offset);
+	}
+	return NULL;
+}
+
+bool mausb_pkt_has_setup_data(struct mausb_dph *header)
+{
+	/*
+	 * Only control transfer requests with sequence number 0 should have
+	 * setup data - nothing else should ever carry setup data.
+	 */
+	if (header->common.pkt_type == TransferReq) {
+		if ((header->eps_tflags & MAUSB_PKT_TFLAG_TYPE_MASK)
+			== MAUSB_PKT_TFLAG_TYPE_CTRL
+			&& le32_to_cpu(header->seq_num) == 0)
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(mausb_pkt_has_setup_data);
+
+/**
+ * Gets an mausb_pkt structure from a given ms_pkt structure.
+ *
+ * can only be used if this driver created the packet i.e. if you just received
+ * an ms_pkt from another machine, it will not be part of a mausb_pkt.
+ */
+struct mausb_pkt *ms_pkt_to_mausb_pkt(struct ms_pkt *ms_pkt)
+{
+	return container_of(ms_pkt, struct mausb_pkt, pkt);
+}
+
+/**
+ * Creates a mausb_pkt structure from a given ms_pkt structure. Used for parsing
+ * incoming packets.
+ */
+struct mausb_pkt *mausb_pkt_from_ms_pkt(struct ms_pkt *ms_pkt,
+	void (*ms_pkt_destructor)(struct ms_pkt *ms_pkt), gfp_t mem_flags)
+{
+	struct mausb_pkt	*pkt;
+	int			current_offset;
+	int			packet_length;
+
+	pkt = kzalloc(sizeof(struct mausb_pkt), mem_flags);
+	if (NULL == pkt)
+		return NULL;
+
+	pkt->pkt = *ms_pkt;
+	pkt->orig_pkt = ms_pkt;
+	pkt->ms_pkt_destructor = ms_pkt_destructor;
+
+	/* the first portion is always the header */
+	pkt->common = mausb_header_from_ms_pkt(ms_pkt);
+	current_offset = mausb_pkt_header_length(pkt->common);
+	packet_length = pkt->common->length;
+
+	/* checks to see if header is contigious */
+	if (NULL == mausb_get_buf_from_ms_pkt(ms_pkt, 0, current_offset)) {
+
+		mapkt_err("%s: packet header bigger than entry (header is %i"
+			" bytes)\n", __func__, current_offset);
+		kfree(pkt);
+		return NULL;
+	}
+
+	/*
+	 * NOTE: Currently control and management packets must be contigious.
+	 *       data packet headers must also be contigious.
+	 *       (ie: the data must all be in 1 ms_pkt entry).
+	 *
+	 * TODO: handle when a control/management is in more than 1
+	 *       kvec entry
+	 */
+
+	if (MAUSB_PKT_TYPE_DATA ==
+		(pkt->common->pkt_type & MAUSB_PKT_TYPE_MASK)) {
+
+		if (mausb_pkt_has_setup_data(pkt->data)) {
+			pkt->setup = mausb_get_buf_from_ms_pkt(ms_pkt,
+				current_offset, sizeof(*pkt->setup));
+
+			if (NULL == pkt->setup) {
+				mapkt_err("%s: could not get setup data\n",
+					__func__);
+			} else {
+				current_offset += sizeof(*pkt->setup);
+			}
+		}
+
+		if (packet_length > current_offset) {
+			pkt->buffer = mausb_get_buf_from_ms_pkt(ms_pkt,
+				current_offset, packet_length - current_offset);
+
+			/*
+			 * if the remaining data was contigious, treat it as a
+			 * buffer
+			 */
+			if (NULL != pkt->buffer) {
+				pkt->buffer_length =
+					packet_length - current_offset;
+				current_offset += pkt->buffer_length;
+			}
+
+		} else if (packet_length < current_offset) {
+			mapkt_dbg("%s: packet_length:%i, current_offset:%i\n",
+				__func__, packet_length, current_offset);
+		}
+	}
+
+	/* checks to see if there is data after packet */
+	if (NULL != mausb_get_buf_from_ms_pkt(ms_pkt, current_offset, 0))
+		mapkt_warn("%s: Warning: data exists after packet\n", __func__);
+
+	return pkt;
+
+}
+EXPORT_SYMBOL(mausb_pkt_from_ms_pkt);
+
+/**
+ * Fills the ms_pkt of a given mausb_pkt based on fields in the mausb_pkt struct.
+ */
+int mausb_pkt_fill_ms_pkt(struct mausb_pkt *pkt, gfp_t mem_flags)
+{
+	struct ms_pkt		*ms_pkt = &pkt->pkt;
+	unsigned int		ent_length;
+
+	ms_pkt->nents = 0;
+
+	if (NULL != pkt->common) {
+		/* add the header */
+		ent_length = mausb_pkt_header_length(pkt->common);
+		if (0 >= ent_length) {
+			return -EINVAL;
+		}
+
+	} else { /* We should ALWAYS have a header, and we dont... */
+		mapkt_err("%s: header not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->common;
+	ms_pkt->kvec[ms_pkt->nents].iov_len = ent_length;
+	ms_pkt->nents += 1;
+
+	/* If this packet should have data, send it */
+	if (pkt->common->pkt_type == TransferReq ||
+		pkt->common->pkt_type == TransferResp){
+
+		/* add the setup field */
+		if (mausb_pkt_has_setup_data(pkt->data)) {
+			ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->setup;
+			ms_pkt->kvec[ms_pkt->nents].iov_len =
+						sizeof(*pkt->setup);
+			ms_pkt->nents += 1;
+
+		} else if (NULL != pkt->setup) {
+			mapkt_warn("%s: Warning: packet has Setup field, but "
+				"flags in header are not set\n", __func__);
+		}
+
+		if (NULL != pkt->buffer && pkt->nents > 0) {
+			mapkt_err("%s: packet has scatterlist and databuffer\n"
+				, __func__);
+			return -EINVAL;
+		}
+
+		/* add the data buffer */
+		if (NULL != pkt->buffer) {
+			ms_pkt->kvec[ms_pkt->nents].iov_base = pkt->buffer;
+			ms_pkt->kvec[ms_pkt->nents].iov_len =
+				pkt->buffer_length;
+			ms_pkt->nents += 1;
+		}
+	}
+
+	mapkt_dbg("%s: pkt filled with %i entries\n", __func__, ms_pkt->nents);
+
+	return 0;
+}
+
+/**
+ * Calculates the total length of data contained in an ms_pkt (in bytes).
+ * Returns the length of the kvec, or 0 on an error.
+ */
+static int mausb_ms_data_length(struct ms_pkt *pkt)
+{
+	int		i;
+	int		total_length;
+	struct kvec	*current_kvec;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_kvec = &pkt->kvec[i];
+		if (NULL == current_kvec)
+			return -EINVAL;
+		else
+			total_length += current_kvec->iov_len;
+	}
+
+	return total_length;
+}
+
+/**
+ * Calculates the length of the datafield in a given datapacket.
+ */
+static int mausb_pkt_datafield_length(struct mausb_pkt *pkt)
+{
+	int length = 0;
+
+	if (NULL != pkt->buffer)
+		length += pkt->buffer_length;
+	if (0 != pkt->nents)
+		length += mausb_ms_data_length(&pkt->pkt);
+
+	return length;
+}
+
+/**
+ * Parses the packet fields to determine how long the packet is. Returns the
+ * packet length on sucess, or a negative errno on error.
+ */
+int mausb_pkt_length(struct mausb_pkt *pkt)
+{
+	int length;
+
+	/* all packets have this field */
+	switch (pkt->common->pkt_type & MAUSB_PKT_TYPE_MASK) {
+
+	/* Management packets */
+	case MAUSB_PKT_TYPE_MGMT:
+		length = sizeof(*pkt->common);
+		length += MAUSB_MGMT_TOKEN_PAD_LEN;
+
+		/* subtypes without additional data */
+		switch (pkt->common->pkt_type) {
+		case DevResetReq:
+		case DevResetResp:
+		case UpdateDevResp:
+		case DevDisconnectReq:
+		case DevDisconnectResp:
+		case USBDevDisconnectReq:
+		case USBDevDisconnectResp:
+		case SleepReq:
+		case SleepResp:
+		case WakeReq:
+		case WakeResp:
+		case RemoteWakeReq:
+		case RemoteWakeResp:
+		case PingReq:
+		case PingResp:
+		case DevInitDisconnectReq:
+		case DevInitDisconnectResp:
+		case SyncResp:
+			break;
+
+		/* subtypes with constant length additional data */
+		case CapReq:
+			length += sizeof(pkt->mgmt->cap_req);
+			break;
+		case CapResp:
+			length += sizeof(pkt->mgmt->cap_resp);
+			/* also include length of any descriptors */
+			length += pkt->mgmt->cap_resp.desc_length;
+			break;
+		case USBDevHandleReq:
+			length += sizeof(pkt->mgmt->usb_dev_handle_req);
+			break;
+		case USBDevHandleResp:
+			length += sizeof(pkt->mgmt->usb_dev_handle_resp);
+			break;
+		case ModifyEP0Req:
+			length += sizeof(pkt->mgmt->modify_ep0_req);
+			break;
+		case ModifyEP0Resp:
+			length += sizeof(pkt->mgmt->modify_ep0_resp);
+			break;
+		case SetUSBDevAddrReq:
+			length += sizeof(pkt->mgmt->set_dev_addr_req);
+			break;
+		case SetUSBDevAddrResp:
+			length += sizeof(pkt->mgmt->set_dev_addr_resp);
+			break;
+		case UpdateDevReq:
+			length += sizeof(pkt->mgmt->update_dev_req);
+			break;
+		case SyncReq:
+			length += sizeof(pkt->mgmt->synch_req);
+			break;
+		case EPCloseStreamReq:
+			length += sizeof(pkt->mgmt->ep_close_stream_req);
+			break;
+		case CancelTransferReq:
+			length += sizeof(pkt->mgmt->cancel_transfer_req);
+			break;
+		case CancelTransferResp:
+			length += sizeof(pkt->mgmt->cancel_transfer_resp);
+			break;
+		case EPOpenStreamReq:
+			length += sizeof(pkt->mgmt->ep_open_stream_req);
+			break;
+		/* subtypes with variable length additional data */
+		case EPHandleReq:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_req.num_ep_des *
+				pkt->mgmt->ep_handle_req.size_ep_des;
+			break;
+		case EPHandleResp:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_resp.num_ep_des *
+				sizeof(struct mausb_ep_des);
+			break;
+		case EPActivateReq:
+		case EPActivateResp:
+		case EPInactivateReq:
+		case EPInactivateResp:
+		case EPResetReq:
+		case EPResetResp:
+		case EPClearTransferReq:
+		case EPClearTransferResp:
+		case EPHandleDeleteReq: /* FALLTHROUGH */
+		case EPHandleDeleteResp:
+			length += sizeof(__u32);
+			length += pkt->mgmt->ep_handle_delete.num_ep
+				* sizeof(struct mausb_ep_handle);
+			break;
+		case EPCloseStreamResp:
+		case USBDevResetReq:
+		case USBDevResetResp:
+		case EPOpenStreamResp:
+		case VendorSpecificReq:
+		case VendorSpecificResp:
+			mapkt_err("%s: cannot determine length of %s packet -"
+				" packet type not yet handled\n", __func__,
+				mausb_type_to_string(pkt->common->pkt_type));
+			BUG();
+			break;
+		default:
+			mapkt_err("%s: invalid management packet type %x\n",
+				__func__, pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+
+		break;
+
+	/* Control Packets */
+	case MAUSB_PKT_TYPE_CTRL:
+		length = sizeof(struct mausb_ctrl_pkt);
+		switch (pkt->common->pkt_type) {
+		case TransferSetupReq:
+			length += sizeof(struct mausb_TransferSetupReq_flds);
+			break;
+		case TransferSetupResp:
+			break;
+		case TransferTearDownConf:
+			break;
+		default:
+			mapkt_err("%s: invalid control packet type %x\n",
+				__func__, pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+		break;
+
+	/* Data Packets */
+	case MAUSB_PKT_TYPE_DATA:
+
+		length = sizeof(struct mausb_dph);
+
+		switch (pkt->common->pkt_type) {
+		case TransferReq:
+		case TransferResp: /* FALLTHROUGH */
+			if (mausb_pkt_has_setup_data(pkt->data))
+				length += sizeof(*pkt->setup);
+
+			length += mausb_pkt_datafield_length(pkt);
+			break;
+		case TransferAck:
+			break;
+		case IsochTransferReq:
+		case IsochTransferResp: /* FALLTHROUGH */
+			length = sizeof(struct mausb_iso_dph);
+			length += mausb_pkt_datafield_length(pkt);
+
+			break;
+		default:
+			mapkt_err("%s: invalid data packet type %x\n", __func__,
+				pkt->common->pkt_type);
+			BUG();
+			break;
+		}
+		break;
+
+	default:
+		mapkt_err("%s: invalid packet type %x\n", __func__,
+			pkt->common->pkt_type);
+		BUG();
+		break;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(mausb_pkt_length);
+
+/**
+ * Finds and returns the memory location offset a number of bytes from a
+ * CapResp packet. Used to find or place device capability descriptors in
+ * a CapResp packet.
+ */
+struct mausb_dev_cap_desc *cap_desc_ptr_increment(struct mausb_mgmt_pkt *resp,
+						  int offset)
+{
+	struct mausb_dev_cap_desc *desc;
+	char  *temp;
+
+	temp = (char *) resp;
+	temp += offset;
+
+	desc  =  (struct mausb_dev_cap_desc *) (temp);
+
+	return desc;
+}
+EXPORT_SYMBOL(cap_desc_ptr_increment);
+
diff --git a/drivers/staging/mausb/drivers/mausb_pkt.h b/drivers/staging/mausb/drivers/mausb_pkt.h
new file mode 100644
index 0000000..fe959c7
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_pkt.h
@@ -0,0 +1,914 @@
+/* name:	mausb_pkt.h
+ * description:	library of MA USB packet structures
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_PKT_H__
+#define __MAUSB_PKT_H__
+
+#include <linux/usb/ch9.h>
+#include "mausb_msapi.h"
+
+#ifdef DEBUG
+#define mapkt_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mapkt_dbg(format, arg...)
+#endif
+
+#define mapkt_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mapkt_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* protocol Version, per section 6.2.1.1 */
+#define MAUSB_VERSION_1_0     0x0
+#define MAUSB_VERSION_MASK    0x0F
+
+/* packet Flags, per section 6.2.1.2 */
+#define MAUSB_PKT_FLAG_MASK       0xF0
+#define MAUSB_PKT_FLAG_HOST       (1 << 4)
+#define MAUSB_PKT_FLAG_RETRY      (1 << 5)
+#define MAUSB_PKT_FLAG_TIMESTAMP  (1 << 6)
+
+/* packet Types, per section 6.2.1.3 */
+#define MAUSB_PKT_TYPE_MASK       0xC0
+#define MAUSB_PKT_TYPE_MGMT       (0 << 6)
+#define MAUSB_PKT_TYPE_CTRL       (1 << 6)
+#define MAUSB_PKT_TYPE_DATA       (2 << 6)
+
+/* packet Subtypes, section 6.2.1.3 */
+#define MAUSB_SUBTYPE_MASK        0x3F
+
+enum mausb_pkt_type {
+	/* Management packets */
+	CapReq = 0x00 | MAUSB_PKT_TYPE_MGMT,
+	CapResp               , /* 1 */
+	USBDevHandleReq       , /* 2 */
+	USBDevHandleResp      , /* 3 */
+
+	EPHandleReq           , /* 4 */
+	EPHandleResp          , /* 5 */
+	EPActivateReq         , /* 6 */
+	EPActivateResp        , /* 7 */
+	EPInactivateReq       , /* 8 */
+	EPInactivateResp      , /* 9 */
+	EPResetReq            , /* 10 */
+	EPResetResp           , /* 11 */
+	EPClearTransferReq    , /* 12 */
+	EPClearTransferResp   , /* 13 */
+	EPHandleDeleteReq     , /* 14 */
+	EPHandleDeleteResp    , /* 15 */
+
+	DevResetReq           , /* 16 */
+	DevResetResp          , /* 17 */
+	ModifyEP0Req          , /* 18 */
+	ModifyEP0Resp         , /* 19 */
+	SetUSBDevAddrReq      , /* 20 */
+	SetUSBDevAddrResp     , /* 21 */
+	UpdateDevReq          , /* 22 */
+	UpdateDevResp         , /* 23 */
+	USBDevDisconnectReq   , /* 24 */
+	USBDevDisconnectResp  , /* 25 */
+
+	USBSuspendReq         , /* 26 */
+	USBSuspendResp        , /* 27 */
+	USBResumeReq          , /* 28 */
+	USBResumeResp         , /* 29 */
+	RemoteWakeReq         , /* 30 */
+	RemoteWakeResp        , /* 31 */
+	PingReq               , /* 32 */
+	PingResp              , /* 33 */
+	DevDisconnectReq      , /* 34 */
+	DevDisconnectResp     , /* 35 */
+	DevInitDisconnectReq  , /* 36 */
+	DevInitDisconnectResp , /* 37 */
+	SyncReq               , /* 38 */
+	SyncResp              , /* 39 */
+	CancelTransferReq     , /* 40 */
+	CancelTransferResp    , /* 41 */
+	EPOpenStreamReq       , /* 42 */
+	EPOpenStreamResp      , /* 43 */
+	EPCloseStreamReq      , /* 44 */
+	EPCloseStreamResp     , /* 45 */
+	USBDevResetReq        , /* 46 */
+	USBDevResetResp       , /* 47 */
+
+	DevNotificationReq    , /* 48 */
+	DevNotificationResp   , /* 49 */
+	EPSetKeepAliveReq     , /* 50 */
+	EPSetKeepAliveResp    , /* 51 */
+	GetPortBWReq          , /* 52 */
+	GetPortBWResp         , /* 53 */
+	SleepReq              , /* 54 */
+	SleepResp             , /* 55 */
+	WakeReq               , /* 56 */
+	WakeResp              , /* 57 */
+
+	/* Vendor-Specific Management Packets */
+	VendorSpecificReq = 0x3E | MAUSB_PKT_TYPE_MGMT,
+	VendorSpecificResp    ,
+
+	/* Control Packets */
+	TransferSetupReq = 0x00 | MAUSB_PKT_TYPE_CTRL,
+	TransferSetupResp     ,
+	TransferTearDownConf  ,
+
+	/* Data Packets */
+	TransferReq = 0x00 | MAUSB_PKT_TYPE_DATA,
+	TransferResp = 0x01 | MAUSB_PKT_TYPE_DATA,
+	TransferAck           ,
+	IsochTransferReq      ,
+	IsochTransferResp
+};
+
+/* Endpoint Handle Fields, per section 6.2.1.5 */
+struct __packed mausb_ep_handle {
+	union {
+		struct {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+			__le16 dir:1;      /**< Direction Field    */
+			__le16 ep_num:4;   /**< Endpoint Number    */
+			__le16 dev_addr:7; /**< USB Device Address */
+			__le16 bus_num:4;  /**< Bus Number         */
+#else
+			__le16 bus_num:4;  /**< Bus Number         */
+			__le16 dev_addr:7; /**< USB Device Address */
+			__le16 ep_num:4;   /**< Endpoint Number    */
+			__le16 dir:1;      /**< Direction Field    */
+#endif
+		};
+		__u16 handle;
+	};
+};
+
+#define MAUSB_VIRTUAL_BUS_NUM 15
+
+/* The least significant bit of the packet is only set to 1 in */
+/* response packets. */
+#define MAUSB_PKT_RESP_FLAG       0x01
+
+/** Status Code Values, per section 6.2.1.8, Table 6 */
+enum mausb_pkt_status {
+	SUCCESS = 0,
+	UNSUCCESSFUL = 128,
+	INVALID_MA_USB_SESSION_STATE,
+	INVALID_DEVICE_HANDLE,
+	INVALID_EP_HANDLE,
+	INVALID_EP_HANDLE_STATE,
+	INVALID_REQUEST,
+	MISSING_SEQUENCE_NUMBER,
+	TRANSFER_PENDING,
+	TRANSFER_EP_STALL,
+	TRANSFER_SIZE_ERROR,
+	TRANSFER_DATA_BUFFER_ERROR,
+	TRANSFER_BABBLE_DETECTED,
+	TRANSFER_TRANSACTION_ERROR,
+	TRANSFER_SHORT_TRANSFER,
+	TRANSFER_CANCELLED,
+	INSUFFICENT_RESOURCES,
+	NOT_SUFFICENT_BANDWIDTH,
+	INTERNAL_ERROR,
+	DATA_OVERRUN,
+	DEVICE_NOT_ACCESSED,
+	BUFFER_OVERRUN,
+	BUSY,
+	DROPPED_PACKET,
+	ISOC_TIME_EXPIRED,
+	ISOCH_TIME_INVALID,
+	NO_USB_PING_RESPONSE,
+	NOT_SUPPORTED,
+	REQUEST_DENIED
+};
+
+/* Status codes NO_ERROR and SUCCESS are interchangeable. */
+#define NO_ERROR SUCCESS
+
+/* MA USB packet header size, per 6.2.1 */
+#define MAUSB_PKT_HEADER_SIZE	12
+
+/** common header fields, per section 6.2.1 */
+struct __packed mausb_pkt_common {
+	/* DWORD 0 */
+	__u8                  ver_flags;   /**< MA USB version & Flags */
+	enum mausb_pkt_type   pkt_type:8;  /**< type and subtype */
+	__le16                 length;     /**< length (in bytes) */
+	/* DWORD 1 */
+	union {
+		struct mausb_ep_handle ep_handle; /**< Endpoint Handle */
+		__le16                  dev_handle;/**< Device Handle */
+	};
+	__u8                  ma_dev_addr;/**< MA USB Device Address */
+	__u8                  mass_id;    /**< MA USB Service Set (MSS) id*/
+	/* DWORD 2 */
+	enum mausb_pkt_status pkt_status:8; /**< packet status code */
+};
+
+/** MA USB Global Time, per section 6.6.1 */
+struct __packed mausb_time {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	/** value of delta field in ITP, defined in USB 3.1 spec. */
+	__le32 delta:13;
+	/** nominal bus interval, Indicates USB microframe number */
+	__le32 nom_bus_itvl:19;
+#else
+	__le32 nom_bus_itvl:19;
+	__le32 delta:13;
+#endif
+};
+
+#define MAUSB_PKT_WSE_NO_DOCK  0
+#define MAUSB_PKT_WSE_DOCK_2_0 1
+#define MAUSB_PKT_WSE_DOCK_3_0 2
+
+/**
+ * MAUSB Device Functionality Support Speed
+ *
+ * mausb_dev_bfs_speed are used for the bFunctionalitySupport field.
+ * Note that they are different values than usb_device_speed.
+ */
+enum mausb_dev_bfs_speed {
+	MAUSB_LOW_SPEED = 0,
+	MAUSB_FULL_SPEED,
+	MAUSB_HIGH_SPEED,
+	MAUSB_SUPER_SPEED,
+	MAUSB_SUPER_SPEED_PLUS,
+	MAUSB_INVALID_SPEED
+};
+
+/* MA USB Capability Request fields, per 6.3.2, table 7 */
+struct __packed mausb_CapReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 max_mgmt_reqs:12; /**< max # of outstanding mgmt reqs to host */
+	__le32 rsvd:20; /**< reserved */
+#else
+	__le32 rsvd:20; /**< reserved */
+	__le32 max_mgmt_reqs:12; /**< max # of outstanding mgmt reqs to host */
+#endif
+};
+
+#define MAUSB_DEV_TYPE_INTEGRATED 0
+#define MAUSB_DEV_TYPE_HS_HUB 1
+#define MAUSB_DEV_TYPE_SS_HUB 2
+
+/** MA USB Capability Response fields, per 6.3.3, table 12 */
+struct __packed mausb_CapResp_flds {
+	__le16 num_ep;       	/**< number of endpoints */
+	__u8  num_dev;      	/**< number of devices */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__u8  num_stream:5; /**< 2^this value = max streams supported */
+	__u8  dev_type:3;   /**< 0 = not a hub, 1 = 2.0 hub, 2 = 3.1 hub */
+#else
+	__u8  dev_type:3;   /**< 0 = not a hub, 1 = 2.0 hub, 2 = 3.1 hub */
+	__u8  num_stream:5; /**< 2^this value = max streams supported */
+#endif
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 desc_count:8;    /**< descriptors count */
+	__le32 desc_length:24;  /**< total length of descriptors */
+#else
+	__le32 desc_length:24;  /**< total length of descriptors */
+	__le32 desc_count:8;    /**< descriptors count */
+#endif
+
+	__le16 max_tx_reqs;     /**< max # of outstanding transfer reqs */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 max_mgmt_reqs:12;/**< max # of outstanding management reqs */
+	__le16 rsvd:4;          /**< reserved */
+#else
+	__le16 rsvd:4;          /**< reserved */
+	__le16 max_mgmt_reqs:12;/**< max # of outstanding management reqs */
+#endif
+};
+
+/** MA USB Device Capability Type Values, per 6.3.3, table 14 */
+enum mausb_dev_cap_type {
+	MAUSB_DEV_CAP_SPEED = 0,
+	MAUSB_DEV_CAP_POUT,
+	MAUSB_DEV_CAP_ISO,
+	MAUSB_DEV_CAP_SYNC,
+	MAUSB_DEV_CAP_CONT_ID,
+	MAUSB_DEV_CAP_LINK_SLEEP
+};
+
+/** Speed Capability Speed Enumeration, per 6.3.3.1 */
+enum mausb_dev_cap_speed_speed {
+	MAUSB_DEV_CAP_SPEED_LOW = 0,
+	MAUSB_DEV_CAP_SPEED_FULL,
+	MAUSB_DEV_CAP_SPEED_HIGH,
+	MAUSB_DEV_CAP_SPEED_SUPER,
+	MAUSB_DEV_CAP_SPEED_SS_PLUS
+};
+
+/** Speed Capability Descriptor, per 6.3.3.1 */
+struct __packed mausb_dev_cap_speed {
+	/* DWORD n+0 */
+	__u8 rsvd_0:4;                          /**< Reserved */
+	enum mausb_dev_cap_speed_speed speed:4; /**< USB Device Speed */
+	__u8 rsvd_1:4;                          /**< Reserved */
+	__u8 lse:2;                             /**< Lane Speed Exponent */
+	__u8 st:2;                              /**< Sublink Type */
+
+	/* DWORD n+1 */
+	__u8  rsvd_2:2;			/**< Reserved */
+	__u8  lane_count:4;		/**< Lane Count */
+	__u8  link_protocol:2;		/**< Link Protocol */
+	__le16 lsm;			/**< Lane Speed Mantissa */
+};
+
+#define MAUSB_DEV_CAP_SPEED_LENGTH 7
+
+/** P-Managed OUT Capabilities Descriptor, per 6.3.3.2 */
+struct __packed mausb_dev_cap_pout {
+	__u8 elastic_buf_cap:1;		/**< Elastic Buffer Capability */
+	__u8 drop_notif:1;		/**< Drop Notification */
+	__u8 rsvd:6;			/**< Reserved */
+
+};
+
+#define MAUSB_DEV_CAP_POUT_LENGTH 3
+
+/** Isochronous Capabilities Descriptor, per 6.3.3.3 */
+struct __packed mausb_dev_cap_iso {
+	__u8 iso_alignment:1;	/**< Isochronous Payload Alignment */
+	__u8 rsvd:7;		/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_ISO_LENGTH 3
+
+/** Synchronization Capabilities Descriptor, per 6.3.3.4 */
+struct __packed mausb_dev_cap_sync {
+	__u8 media_time_avail:1;	/**< Media Time Available */
+	__u8 timestamp_req:1;		/**< Timestamp Request */
+	__u8 rsvd:6;			/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_SYNCH_LENGTH 3
+
+/** Container ID Capability Descriptor, per 6.3.3.5 */
+struct __packed mausb_dev_cap_cont_id {
+	long long int cont_id_upper;	/**< 64 msb of Container ID */
+	long long int cont_id_lower;	/**< 64 lsb of Container ID */
+};
+
+#define MAUSB_DEV_CAP_CONT_ID_LENGTH 18
+
+/** Link Sleeo Capability Descriptor, per 6.3.3.6 */
+struct __packed mausb_dev_cap_link_sleep {
+	__u8 link_sleep_cap:1;		/**< Link Sleep Capable */
+	__u8 rsvd:7;			/**< Reserved */
+};
+
+#define MAUSB_DEV_CAP_LINK_SLEEP_LENGTH 3
+
+/** MA Device Capability Descriptor  */
+struct __packed mausb_dev_cap_desc {
+	/* common descriptor fields */
+	__u8 length;				/**< Descriptor length */
+	enum mausb_dev_cap_type cap_type:8;     /**< Capability type */
+
+	/* Descriptor-specific format */
+	union {
+		struct mausb_dev_cap_speed      speed;
+		struct mausb_dev_cap_pout       pout;
+		struct mausb_dev_cap_iso        iso;
+		struct mausb_dev_cap_sync       sync;
+		struct mausb_dev_cap_cont_id    cont_id;
+		struct mausb_dev_cap_link_sleep link_sleep;
+	};
+};
+
+/** USB Device Handle Request fields, per 6.3.4, table 8 */
+struct __packed mausb_USBDevHandleReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 usb_rt_str:20;     /**< USB Route String, per USB3.0 Spec */
+	__le32 speed:4;           /**< USB Device Speed */
+	__le32 rsvd_0:8;          /**< reserved */
+	__le16 dock_hub;          /**< dock hub device handle */
+	__le16 rsvd_1;            /**< reserved */
+	__le16 parent_hub;        /**< parent hub handle (if LS or HS) */
+	__u8  parent_hub_port:4;  /**< parent hub port   (if LS or HS) */
+	__u8  mtt:1;              /**< multiple transaction translators */
+	__le16 rsvd_2:15;         /**< reserved */
+	__u8  lse:2;		  /**< lane speed exponent */
+	__u8  st:2;		  /**< sublink type */
+	__u8  rsvd_3:2;		  /**< reserved */
+	__u8  lane_count:2;	  /**< lane count */
+	__u8  link_protocol:2;	  /**< link protocol */
+	__le16 lsm;		  /**< lane speed mantissa */
+
+#else
+	__le16 lsm;		  /**< lane speed mantissa */
+	__u8  link_protocol:2;	  /**< link protocol */
+	__u8  lane_count:2;	  /**< lane count */
+	__u8  rsvd_3:2;		  /**< reserved */
+	__u8  st:2;		  /**< sublink type */
+	__u8  lse:2;		  /**< lane speed exponent */
+	__le16 rsvd_2:15;         /**< reserved */
+	__u8  mtt:1;              /**< multiple transaction translators */
+	__u8  parent_hub_port:4;  /**< parent hub port   (if LS or HS) */
+	__le16 parent_hub;        /**< parent hub handle (if LS or HS) */
+	__le16 rsvd_1;            /**< reserved */
+	__le16 dock_hub;          /**< dock hub device handle */
+	__le32 rsvd_0:8;          /**< reserved */
+	__le32 speed:4;           /**< USB Device Speed */
+	__le32 usb_rt_str:20;     /**< USB Route String, per USB3.0 Spec */
+#endif
+};
+
+/* maximum number of EPs in a packet array */
+#define MAUSB_PKT_MAX_NUM_EP 31
+
+/* EPHandleReq constants, per section 6.3.6 */
+#define MAUSB_EP_REQ_SIZE 8
+#define MAUSB_EP_REQ_PADDING (MAUSB_EP_REQ_SIZE - USB_DT_ENDPOINT_SIZE)
+#define MAUSB_SS_EP_REQ_SIZE 16
+#define MAUSB_SS_EP_REQ_PADDING (MAUSB_SS_EP_REQ_SIZE - \
+		(USB_DT_ENDPOINT_SIZE + USB_DT_SS_EP_COMP_SIZE))
+
+/** packed USB endpoint descriptor */
+struct __packed mausb_ep_req {
+	unsigned char ep_des[USB_DT_ENDPOINT_SIZE];
+	unsigned char padding[MAUSB_EP_REQ_PADDING];
+};
+
+/** packed SuperSpeed USB endpoint descriptor */
+struct __packed mausb_ss_ep_req {
+	unsigned char ep_des[USB_DT_ENDPOINT_SIZE];
+	unsigned char ss_ep_comp_des[USB_DT_SS_EP_COMP_SIZE];
+	unsigned char padding[MAUSB_SS_EP_REQ_PADDING];
+};
+
+/** Endpoint Handle Request fields, per 6.3.6, Tables 10 & 11 */
+struct __packed mausb_EPHandleReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep_des:5;  /**< number of EP descriptors in the packet */
+	__le32 size_ep_des:6; /**< size of EP descriptors (in bytes) */
+	__le32 rsvd:21;        /**< reserved */
+#else
+	__le32 rsvd:21;
+	__le32 size_ep_des:6;
+	__le32 num_ep_des:5;
+#endif
+	/** array of endpoint descriptors (Standard or SuperSpeed) */
+	union {
+		struct mausb_ep_req ep_des[MAUSB_PKT_MAX_NUM_EP]
+			__aligned(4);
+		struct mausb_ss_ep_req ss_ep_des[MAUSB_PKT_MAX_NUM_EP]
+			__aligned(4);
+		/* TODO: structure for USB 3.1 devices with ISO endpoints */
+	};
+};
+
+
+/** WEP Descriptor format, per 6.3.7, table 13 */
+struct __packed mausb_ep_des {
+	struct mausb_ep_handle ep_handle; /**< requested endpoint handle */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 dir:1;        /**< direction */
+	__le16 iso:1;        /**< isochronous */
+	__le16 l_man:1;      /**< L-managed transfers */
+	__le16 valid:1;      /**< valid handle bit */
+	__le16 rsvd_0:12;    /**< reserved */
+#else
+	__le16 rsvd_0:12;    /**< reserved */
+	__le16 valid:1;      /**< valid handle bit */
+	__le16 l_man:1;      /**< L-managed transfers */
+	__le16 iso:1;        /**< isochronous */
+	__le16 dir:1;        /**< direction */
+#endif
+	__le16 ccu;          /**< credit consumption unit */
+	__le16 rsvd_1;       /**< reserved */
+	__le32 buffer_size;  /**< buffer size (in bytes) */
+	__le16 iso_prog_dly; /**< max iso programming delay (in uSec) */
+	__le16 iso_resp_dly; /**< max iso response delay (in uSec) */
+};
+
+/** Endpoint Handle Response fields, per 6.3.7, Tables 12 & 13 */
+struct __packed mausb_EPHandleResp_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep_des:5; /**< number of EP descriptors in this packet */
+	__le32 rsvd:27;      /**< reserved */
+#else
+	__le32 rsvd:27;      /**< reserved */
+	__le32 num_ep_des:5; /**< number of EP descriptors in this packet */
+#endif
+	struct mausb_ep_des ep_des[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Endpoint Handle Delete fields, per 6.3.16 & 6.3.17, Tables 37 & 38 */
+/*
+ * Note: both the request and response packets are in the same format.
+ * The the request contains all the handles to delete, and the
+ * response indicates how many were deleted.
+ */
+struct __packed mausb_EPHandleDelete_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 num_ep:5; /**< number of EP descriptors */
+	__le32 rsvd:27;  /**< reserved */
+#else
+	__le32 rsvd:27;  /**< reserved */
+	__le32 num_ep:5; /**< number of EP descriptors */
+#endif
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Modify EP0 Request and Response fields, per 6.3.20-21, table 39 & 40 */
+struct __packed mausb_ModifyEP0_flds {
+	/** Endpoint 0 handle for the device */
+	struct mausb_ep_handle ep_handle;
+	union {
+		__le16 max_pkt_size; /**< Maximum packet size for EP0 */
+		__le16 rsvd; 	     /**< reserved */
+	};
+};
+
+/** Set USB Device Address Request fields, per 6.3.22, table 41 */
+struct __packed mausb_SetDevAddrReq_flds {
+	__le16  resp_timeout; /**< time the device has to respond (in ms) */
+	__le16  rsvd;
+};
+
+/** Set USB Device Address Response fields, per 6.3.23, table 42 */
+struct __packed mausb_SetDevAddrResp_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32  dev_addr:7; /**< USB Device Address from request */
+	__le32  rsvd:25;
+#else
+	__le32  rsvd:25;
+	__le32  dev_addr:7; /**< USB Device Address from request */
+#endif
+};
+
+/** Update Device Request fields, per 6.3.24, Table 28 */
+struct __packed mausb_UpdateDevReq_flds {
+	__le16 max_exit_lat; /**< Max Exit Latency */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__u8  hub:1;        /**< Hub flag, set to 1 if hub */
+	__u8  num_ports:4;  /**< hub only, number of downward-facing ports */
+	__u8  mtt:1;        /**< HS hub only, Multiple Transaction Translator */
+	__u8  ttt:2;        /**< HS hub only, Transaction Think Time */
+	/**< 0 = at most 8  FS bit times */
+	/**< 1 = at most 16 FS bit times */
+	/**< 2 = at most 24 FS bit times */
+	/**< 3 = at most 32 FS bit times */
+#else
+	__u8  ttt:2;
+	__u8  mtt:1;
+	__u8  num_ports:4;
+	__u8  hub:1;
+#endif
+};
+
+/** MAUSB Synchronization Request fields, per 6.3.40, Table 30 */
+struct __packed mausb_SynchReq_flds {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16             td_valid:1; /**< Transmission Delay field valid */
+	__le16             rsvd:15;    /**< reserved */
+#else
+	__le16             rsvd:15;    /**< reserved */
+	__le16             td_valid:1; /**< Transmission Delay field valid */
+#endif
+	struct mausb_time timestamp;   /**< MA USB Timestamp, per 6.5.1.11 */
+	__le32             tx_dly;     /**< Transmission delay, per 6.5.1.12 */
+};
+
+/** Cancel Transfer Request fields, per 6.3.42, Table 31 */
+struct __packed mausb_CancelTransferReq_flds {
+	struct mausb_ep_handle ep_handle;	/**< Target Endpoint Handle */
+	__le16                  stream_id;	/**< Target stream ID */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32                  req_id:8;	/**< Target request ID */
+	__le32                  rsvd:24;	/**< reserved */
+#else
+	__u32                  rsvd:24;    /**< reserved */
+	__u32                  req_id:8;    /**< Target request ID */
+#endif
+};
+
+/** Cancel Transfer Response fields, per 6.3.43, Table 32 */
+struct __packed mausb_CancelTransferResp_flds {
+	struct mausb_ep_handle ep_handle;
+	__u16 stream_id;
+	/** Cancellation status                         */
+	/** 0 = Cancel Error                            */
+	/** 1 = Cancel Sucess before any data was moved */
+	/** 2 = Cancel Sucess after some data was moved */
+	/** 3 = Transfer not found                      */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 req_id:8;
+	__le32 cancel_status:2;
+	__le32 rsvd_0:22;
+#else
+	__le32 rsvd_0:22;
+	__le32 cancel_status:2;
+	__le32 req_id:8;
+#endif
+	/** Delivered Sequence Number */
+	/** For OUT Transfers only. Only valid if cancel_status = 2 */
+	/** Indicates last sequence number delivered to the device. */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 deliv_seq_num:24;
+	__le32 rsvd_1:8;
+#else
+	__le32 deliv_seq_num:24;
+	__le32 rsvd_1:8;
+#endif
+	/** Delivered Byte Offset. Only valid if cancel_status = 2 */
+	__le32 deliv_byte_offset;
+};
+
+/** Enpoint Open Stream Request fields, per 6.3.44, Table 33 */
+struct __packed mausb_EPOpenStreamReq_flds {
+	struct mausb_ep_handle ep_handle; /**< Target bulk endpoint */
+	__le32  num_streams:17; /**< number of streams to be opened */
+	__le32  rsvd:7;
+};
+
+/** Enpoint Inactivate Request fields, per 6.3.10, Table 30 */
+struct __packed mausb_EPInactivateReq_flds {
+	__u8  num_ep_handles:5; /** number of ep handles included packet */
+	__u8  suspend_flg:1; /** indicates if issued due to suspension of */
+			     /** included endpoints */
+			     /** 0 = endpoints not suspended */
+			     /** 1 = endpoints suspended */
+	__u32  rsvd:26;
+
+	/** list of EP handles MA USB host is requesting to inactivate */
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+/** Enpoint Inactivate Response fields, per 6.3.11, Table 33 */
+struct __packed mausb_EPInactivateResp_flds {
+	__u8  num_ep_with_error:5; /** number of EP handles with */
+				   /** unsuccessful inactivation */
+				   /** should only be non-zero if */
+				   /** packet status is not SUCCESS */
+	__u32  rsvd:27;
+
+	/** list of EP handles whose inactivation failed */
+	struct mausb_ep_handle ep_handle[MAUSB_PKT_MAX_NUM_EP];
+};
+
+#define MAUSB_MGMT_MAX_TOKEN ((1 << 10) - 1)
+#define MAUSB_MGMT_TOKEN_PAD_LEN 3 /* token + pad to DWORD */
+
+/** Management Packet fields, per 6.3.1 */
+struct __packed mausb_mgmt_pkt {
+	struct mausb_pkt_common common;
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16                  token:10;
+	__le16                  padding:6; /* for DWORD alignment */
+#else
+	__le16                  padding:6; /* for DWORD alignment */
+	__le16                  token:10;
+#endif
+	__u8                    padding_2;
+	union {
+		struct mausb_CapReq_flds             cap_req;
+		struct mausb_CapResp_flds            cap_resp;
+		struct mausb_USBDevHandleReq_flds    usb_dev_handle_req;
+		__le16                                usb_dev_handle_resp;
+		struct mausb_EPHandleReq_flds        ep_handle_req;
+		struct mausb_EPHandleResp_flds       ep_handle_resp;
+		struct mausb_EPHandleDelete_flds     ep_handle_delete;
+		struct mausb_ModifyEP0_flds          modify_ep0_req;
+		struct mausb_ModifyEP0_flds          modify_ep0_resp;
+		struct mausb_SetDevAddrReq_flds      set_dev_addr_req;
+		struct mausb_SetDevAddrResp_flds     set_dev_addr_resp;
+		struct mausb_UpdateDevReq_flds       update_dev_req;
+		struct mausb_SynchReq_flds           synch_req;
+		__le16                                ep_close_stream_req;
+		struct mausb_CancelTransferReq_flds  cancel_transfer_req;
+		struct mausb_CancelTransferResp_flds cancel_transfer_resp;
+		struct mausb_EPOpenStreamReq_flds    ep_open_stream_req;
+		struct mausb_EPInactivateReq_flds    ep_inactivate_req;
+		struct mausb_EPInactivateResp_flds   ep_inactivate_resp;
+
+		/* TODO: add remaining management packet data */
+
+	};
+};
+
+/** Transfer Setup Request fields, per 6.4.1, Table 38 */
+struct __packed mausb_TransferSetupReq_flds {
+	/** Identifies link type     */
+	/** 0     = Reserved         */
+	/** 1     = IEEE 802.11 link */
+	/** 2-255 = Reserved         */
+	__u8 link_type;
+	/** Connection ID data is dependant on Link Type */
+	union {
+		/** for 802.11 links (link_type == 1) */
+		struct __packed {
+			__u8 tid:4;  /**< Traffic Identifier */
+			__u8 rsvd:4;
+		} connection_id;
+	};
+};
+
+/** Control Packet fields, per 6.4 */
+struct __packed mausb_ctrl_pkt {
+	struct mausb_pkt_common common;
+	struct mausb_TransferSetupReq_flds transfer_setup_req;
+	__u8 padding; /* for header DWORD alignment */
+};
+
+#define MAUSB_PKT_EPS_UNASSIGNED 0
+#define MAUSB_PKT_EPS_ACTIVE     1
+#define MAUSB_PKT_EPS_INACTIVE   2
+#define MAUSB_PKT_EPS_HALTED     3
+
+#define MAUSB_PKT_TFLAG_ARQ  (1 << 2)
+#define MAUSB_PKT_TFLAG_NEG  (1 << 3)
+#define MAUSB_PKT_TFLAG_EOT  (1 << 4)
+#define MAUSB_PKT_TFLAG_TYPE_CTRL (0 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_ISOC (1 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_BULK (2 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_INT  (3 << 5)
+#define MAUSB_PKT_TFLAG_TYPE_MASK 0x60
+
+#define MAUSB_PKT_SEQ_NUM_MASK 0x00FFFFFF
+
+/** Fields common to all datapackets, per 6.5 */
+struct __packed mausb_dph {
+	struct mausb_pkt_common common;
+	__u8   eps_tflags;	/**< EPS & T-Flags */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le16 num_seg:12;
+	__le16 iflags:4;
+#else
+	__le16 iflags:4;
+	__le16 num_seg:12;
+#endif
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__le32 seq_num:24;	/**< Sequence Number */
+	__le32  req_id:8;	/**< request ID */
+#else
+	__le32  req_id:8;	/**< request ID */
+	__le32 seq_num:24;      /**< Sequence Number */
+#endif
+	union {
+		__le32 remaining_size_credit;
+		__le32 present_time;
+	};
+};
+
+/** Fields exclusive to isochronous data packets, per 6.5 */
+struct __packed mausb_iso_dph {
+	struct mausb_dph data;
+	__le32 wse_ts;          /**< WSE Timestamp */
+	__le32 tx_dly;          /**< Transmission Delay */
+};
+
+
+/* unless the urb contains scattergather buffers, a packet will
+ * need at most 3 entries:
+ *	- 1 for the header
+ *	- 1 for the setup data
+ *	- 1 for the data buffer
+ *
+ */
+#define MAUSB_MS_PKT_ORIG_NENTS 4
+
+/**
+ * mausb_pkt structure
+ *
+ * Can be used to parse any type of MAUSB packet, regardless of contents.
+ * If the packet type is known, this structure shouldn't be used. Instead,
+ * a type-specific structure (ie: mausb_XXXX_pkt) should be used.
+ *
+ * @setup:		setup data (control packets only)
+ * @buffer:		data buffer
+ * @buffer_length:	length of data buffer
+ * @pkt_list:		connects packet to other packets in a linked list
+ * @kvec_list:		kvec list
+ * @nents:		number of kvecs
+ * @pkt:		A compilation of all the buffers needed to be sent
+ *			across the medium. Used to pass packet to medium.
+ * @orig_pkt:		Original ms_pkt for this packet. Used for destructor.
+ *	 		If this packet originated from the MA driver, it will
+ *			point to the ms_pkt of this ma_pkt. If it came in from
+ *			the MS driver, it will point at the ms_pkt it sent
+ *			us. This is used by the ms_pkt_destructor, so we can
+ *			make sure we are pointing to the right ms_pkt.
+ */
+struct mausb_pkt {
+	union {
+		struct mausb_pkt_common *common;
+		struct mausb_mgmt_pkt   *mgmt;
+		struct mausb_ctrl_pkt   *ctrl;
+		struct mausb_dph        *data;
+		struct mausb_iso_dph    *iso_data;
+	};
+
+	struct usb_ctrlrequest *setup;
+	void *buffer;
+	u32 buffer_length;
+	struct list_head pkt_list;
+	struct kvec *kvec_list;
+	int nents;
+	struct ms_pkt pkt;
+	struct ms_pkt *orig_pkt;
+	void (*ms_pkt_destructor)(struct ms_pkt *pkt);
+};
+
+enum mausb_pkt_buf_copy_dir {
+	MAUSB_PKT_BUF_COPY_TO_KVEC = 0,
+	MAUSB_PKT_BUF_COPY_FROM_KVEC
+};
+
+void mausb_pkt_buf_copy_kvec(struct mausb_pkt *pkt, int buf_length, int offset,
+			  struct kvec *kv, int nents,
+			   enum mausb_pkt_buf_copy_dir dir);
+
+/* function declarations */
+const char *mausb_type_to_string(enum mausb_pkt_type type);
+int mausb_pkt_fill_ms_pkt(struct mausb_pkt *pkt, gfp_t mem_flags);
+int mausb_pkt_header_length(struct mausb_pkt_common *header);
+enum mausb_pkt_status mausb_errno_to_ma_status(int errno);
+int mausb_to_urb_status(enum mausb_pkt_status pkt_status);
+struct usb_endpoint_descriptor *mausb_ep_handle_req_get_ep_des(
+		struct mausb_EPHandleReq_flds *req, int i);
+int mausb_pkt_length(struct mausb_pkt *pkt);
+struct mausb_pkt *mausb_alloc_pkt(enum mausb_pkt_type pkt_type, int *status,
+		gfp_t memflags);
+int mausb_generate_ms_pkt(struct mausb_pkt *pkt);
+bool mausb_pkt_has_setup_data(struct mausb_dph *header);
+struct mausb_pkt *ms_pkt_to_mausb_pkt(struct ms_pkt *ms_pkt);
+struct mausb_pkt *mausb_pkt_from_ms_pkt(struct ms_pkt *ms_pkt,
+		void (*ms_pkt_destructor)(struct ms_pkt *ms_pkt),
+		gfp_t mem_flags);
+int mausb_pkt_dmux(struct ms_pkt *ms_pkt, void *context);
+void mausb_free_pkt(struct mausb_pkt *pkt);
+bool mausb_pkt_resp(struct mausb_pkt *pkt);
+struct mausb_dev_cap_desc *cap_desc_ptr_increment(struct mausb_mgmt_pkt *resp,
+		int offset);
+
+/* Helper functions for sequence number and request id wraparound */
+u32 mausb_seq_num_add(u32 seq_num, int val);
+void mausb_increment_seq_num(u32 *seq_num);
+bool mausb_seq_num_lt(u32 a, u32 b);
+bool mausb_seq_num_lt_eq(u32 a, u32 b);
+bool mausb_seq_num_gt_eq(u32 a, u32 b);
+bool mausb_seq_num_gt(u32 a, u32 b);
+u8 mausb_req_id_add(u8 req_id, int val);
+bool mausb_req_id_lt(u8 a, u8 b);
+bool mausb_req_id_gt(u8 a, u8 b);
+bool mausb_req_id_gt_eq(u8 a, u8 b);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (2 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  4:21     ` Greg KH
  2014-11-11  2:09   ` [V2 PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
                     ` (6 subsequent siblings)
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we handle media specific packets and transport. The MS driver
interfaces with a media agnostic (MA) driver via a series of transfer pairs.
Transfer pairs consist of a set of functions to pass MA USB packets back
and forth between MA and MS drivers. There is one transfer pair per device
endpoint and one transfer pair for control/management traffic. When the MA
driver needs to send an MA USB packet, it hands the packet off to the MS
layer where the packet is converted into an MS form and sent via TCP over
the underlying ethernet or wireless medium. When the MS driver receives a
packet, it converts it into an MA USB packet and hands it off the the MA
driver for handling.

In addition, the MS driver provides an interface to inititate connection events.
Because there are no physical MA USB ports in an MA USB host, the host must be
notified via software when a device is connected.

Lastly, the MS driver contains a number of ioctl functions that are used by a
utility to adjust medium-related driver parameters and connect or disconnect the
MA USB host and device drivers.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_ioctl.c      | 256 +++++++++++++
 drivers/staging/mausb/drivers/mausb_ioctl.h      | 101 ++++++
 drivers/staging/mausb/drivers/mausb_msapi.c      | 108 ++++++
 drivers/staging/mausb/drivers/mausb_msapi.h      | 232 ++++++++++++
 drivers/staging/mausb/drivers/mausb_tcp-device.c | 147 ++++++++
 drivers/staging/mausb/drivers/mausb_tcp-host.c   | 142 ++++++++
 drivers/staging/mausb/drivers/mausb_tcp.c        | 435 +++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tcp.h        | 129 +++++++
 8 files changed, 1550 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h

diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.c b/drivers/staging/mausb/drivers/mausb_ioctl.c
new file mode 100644
index 0000000..07d2425
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_ioctl.c
@@ -0,0 +1,256 @@
+/* Name:         mausb_ioctl.c
+ * Description:  ioctl functions for MA USB media specific driver
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/usb/gadget.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include "mausb_hcd.h"
+#include "mausb_udc.h"
+#include "mausb_ioctl.h"
+
+/* #define MAUSB_PRINT_IOCTL_MAGIC */
+#define DEBUG
+
+static int ma_open;
+
+/**
+ * This function is used to open the device file in order to read/write
+ * from/to it.
+ *
+ * @inode:	Struct with various information that is passed in when this
+ *		function is called. We don't need to use it for our purposes.
+ * @file:	The file to be opened.
+ */
+static int mausb_open(struct inode *inode, struct file *file)
+{
+	if (ma_open)
+		return -EBUSY;
+	ma_open++;
+	try_module_get(THIS_MODULE);
+
+	return 0;
+}
+
+/**
+ * This function is used to close the device file.
+ *
+ * @inode:	Struct with various information that is passed in when this
+ *		function is called. We don't need to use it for our purposes.
+ * @file:	The file to be closed.
+ */
+static int mausb_release(struct inode *inode, struct file *file)
+{
+	ma_open--;
+	module_put(THIS_MODULE);
+
+	return 0;
+}
+
+
+/**
+ * This function is used to execute ioctl commands, determined by ioctl_func.
+ *
+ * @file:	  The device file. We don't use it directly, but it's passed in.
+ * @ioctl_func:	  This value determines which ioctl function will be used.
+ * @ioctl_buffer: This buffer is used to transfer data to/from the device.
+ */
+long mausb_ioctl(struct file *file, unsigned int ioctl_func,
+		unsigned long ioctl_buffer)
+{
+	char message[BUFFER];
+	int ret, value;
+	unsigned long int long_value;
+	char __user *msg = (char *)ioctl_buffer;
+	char *response;
+
+	switch (ioctl_func) {
+	case IOCTL_GET_VRSN:
+		ret = copy_to_user(msg, DRIVER_VERSION, strlen(DRIVER_VERSION));
+		break;
+	case IOCTL_GET_NAME:
+		ret = copy_to_user(msg, MAUSB_NAME, strlen(MAUSB_NAME));
+		break;
+	case IOCTL_GADGET_C:
+		ret = gadget_connection(1);
+		if (ret >= 0)
+			response = MAUSB_GADGET_C_SUCCESS;
+		else
+			response = MAUSB_GADGET_C_FAIL;
+
+		ret = copy_to_user(msg, response, strlen(response));
+		break;
+	case IOCTL_GADGET_D:
+		ret = gadget_connection(0);
+		if (ret >= 0)
+			response = MAUSB_GADGET_D_SUCCESS;
+		else
+			response = MAUSB_GADGET_D_FAIL;
+
+		ret = copy_to_user(msg, response, strlen(response));
+		break;
+	case IOCTL_SET_PORT:
+		ret = strncpy_from_user(message, msg, BUFFER);
+		if (ret < 0)
+			break;
+		ret = kstrtoint(msg, 0, &value);
+		if (ret != 0)
+			break;
+
+		ret = set_port_no(value);
+		sprintf(message, "PORT NUMBER:%d, Returned %i\n", value,
+			ret);
+		ret = copy_to_user(msg, message, strlen(message));
+		break;
+	case IOCTL_SET_IP:
+		ret = strncpy_from_user(message, msg, BUFFER);
+		if (ret < 0)
+			break;
+		ret = kstrtoul(message, 0, &long_value);
+		if (ret != 0)
+			break;
+
+		ret = set_ip_addr(long_value);
+		sprintf(message, "IP ADDRESS:%lx, returned %i\n",
+			long_value, ret);
+		ret = copy_to_user(msg, message, strlen(message));
+		break;
+	case IOCTL_SET_MAC:
+		{
+			u8 mac[6];
+			int i;
+			ret = copy_from_user(mac, msg, 6);
+			if (ret) {
+				pr_err("copy_from_user failed\n");
+				break;
+			}
+			for (i = 0; i < ETH_ALEN; i++)
+				pr_info("mac[%d]=0x%x\n", i, mac[i]);
+			ret = set_mac_addr(mac);
+			if (ret)
+				pr_err("unable to set MAC addr\n");
+
+			break;
+		}
+	}
+
+	/* failure */
+	if (ret < 0)
+		return ret;
+
+	/* success */
+	return 0;
+}
+
+/**
+ * This struct creates links with our implementations of various entry point
+ * functions.
+ */
+const struct file_operations fops = {
+	.open = mausb_open,
+	.release = mausb_release,
+	.unlocked_ioctl = mausb_ioctl
+};
+
+/**
+ * Registers a character device using our device file. This function is called
+ * in the mausb_hcd_init function.
+ */
+int reg_chrdev()
+{
+	int ret;
+
+#ifdef MAUSB_PRINT_IOCTL_MAGIC
+
+	printk(KERN_DEBUG "Printing IOCTL magic numbers:\n");
+	printk(KERN_DEBUG "IOCTL_SET_MSG        = %u\n", IOCTL_SET_MSG);
+	printk(KERN_DEBUG "IOCTL_GET_MSG        = %u\n", IOCTL_GET_MSG);
+	printk(KERN_DEBUG "IOCTL_GET_VRSN       = %u\n", IOCTL_GET_VRSN);
+	printk(KERN_DEBUG "IOCTL_GET_NAME       = %u\n", IOCTL_GET_NAME);
+	printk(KERN_DEBUG "IOCTL_GADGET_C       = %u\n", IOCTL_GADGET_C);
+	printk(KERN_DEBUG "IOCTL_GADGET_D       = %u\n", IOCTL_GADGET_D);
+	printk(KERN_DEBUG "IOCTL_MED_DELAY      = %u\n", IOCTL_MED_DELAY);
+	printk(KERN_DEBUG "IOCTL_SET_IP         = %u\n", IOCTL_SET_IP);
+	printk(KERN_DEBUG "IOCTL_SET_PORT       = %u\n", IOCTL_SET_PORT);
+	printk(KERN_DEBUG "IOCTL_SET_IP_DECIMAL = %u\n", IOCTL_SET_IP_DECIMAL);
+	printk(KERN_DEBUG "IOCTL_SET_MAC        = %u\n", IOCTL_SET_MAC);
+
+#endif
+
+	ret = register_chrdev(MAJOR_NUM, MAUSB_NAME, &fops);
+
+	if (ret < 0)
+		printk(KERN_ALERT "Registering mausb failed with %d\n", ret);
+	else
+		printk(KERN_INFO "%s registeration complete. Major device"
+			" number %d.\n", MAUSB_NAME, MAJOR_NUM);
+
+	return ret;
+}
+
+/**
+ * Unregisters the character device when the hcd is unregistered. As hinted,
+ * this function is called in the mausb_hcd_exit function.
+ */
+void unreg_chrdev()
+{
+	unregister_chrdev(MAJOR_NUM, MAUSB_NAME);
+}
diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.h b/drivers/staging/mausb/drivers/mausb_ioctl.h
new file mode 100644
index 0000000..4126ade
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_ioctl.h
@@ -0,0 +1,101 @@
+/* Name:         mausb_ioctl.h
+ * Description:  header file for MA USB ioctl functions
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MAUSB_IOCTL_H
+#define MAUSB_IOCTL_H
+
+#define BUFFER 80
+#define DRIVER_VERSION "Alpha 0.0.25"
+#define MAJOR_NUM 100
+
+/* These define the ioctl functions that can be used. */
+#define IOCTL_GET_VRSN _IOR(MAJOR_NUM, 0, char *)
+#define IOCTL_GET_NAME _IOR(MAJOR_NUM, 1, char *)
+#define IOCTL_GADGET_C _IOR(MAJOR_NUM, 2, char *)
+#define IOCTL_GADGET_D _IOR(MAJOR_NUM, 3, char *)
+#define IOCTL_SET_IP   _IOR(MAJOR_NUM, 4, char *)
+#define IOCTL_SET_PORT _IOR(MAJOR_NUM, 5, char *)
+#define IOCTL_SET_MAC  _IOR(MAJOR_NUM, 6, char *)
+
+/* This is the location where the device file will be created. It is used to
+ * read/write to in order to communicate to and from the device. */
+#define DEVICE_FILE_NAME "/dev/mausb"
+
+/* MAC address length */
+#define ETH_ALEN 6
+
+/* Responses to IOCTL calls */
+#define MAUSB_GADGET_C_SUCCESS	"gadget connect process complete"
+#define MAUSB_GADGET_C_FAIL	"gadget connect process failed"
+#define MAUSB_GADGET_D_SUCCESS	"gadget disconnect process complete"
+#define MAUSB_GADGET_D_FAIL	"gadget disconnect process failed"
+
+/* forward declarations */
+struct mausb_udc;
+struct mausb_hcd;
+
+/* Functions for register/unregistering the character device */
+int reg_chrdev(void);
+void unreg_chrdev(void);
+
+/* Medium-defined functions */
+int set_medium_delay(int delay);
+int set_ip_addr(unsigned long in_addr);
+int set_port_no(int port_no);
+int set_mac_addr(unsigned char mac_addr[ETH_ALEN]);
+int gadget_connection(int on);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_msapi.c b/drivers/staging/mausb/drivers/mausb_msapi.c
new file mode 100644
index 0000000..9960e45
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_msapi.c
@@ -0,0 +1,108 @@
+/* Name:	mausb_msapi.c
+ * Description: This file contains helper functions for using the msapi.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include "mausb_msapi.h"
+
+int mausb_transfer_packet(struct ms_pkt *pkt,
+	struct mausb_pkt_transfer *transfer)
+{
+	return transfer->transfer_packet(pkt, transfer->context);
+}
+EXPORT_SYMBOL(mausb_transfer_packet);
+
+/**
+ * Frees the given ms_pkt and associated buffers. This function is not
+ * necessary to use the API, but could be useful on both sides of the interface.
+ */
+void mausb_free_ms_pkt(struct ms_pkt *pkt)
+{
+	int i;
+	void *current_buf;
+
+	for (i = 0; i < pkt->nents; ++i) {
+		current_buf = pkt->kvec[i].iov_base;
+		if (NULL != current_buf) {
+			kfree(current_buf);
+		} else {
+			pr_debug("%s: cannot find buffer for kvec #%i in"
+				" ms_pkt at %p\n", __func__, i, pkt->kvec);
+		}
+	}
+
+	kfree(pkt);
+
+	return;
+}
+EXPORT_SYMBOL(mausb_free_ms_pkt);
+
+/**
+ * Calculates the total length of the data in a ms_pkt. Returns the total
+ * length of the data in the ms_pkt, or a negative errno.
+ */
+int mausb_ms_pkt_length(struct ms_pkt *pkt)
+{
+	int i;
+	int total_length = 0;
+
+	for (i = 0; i < pkt->nents; ++i)
+		total_length += pkt[i].kvec->iov_len;
+
+	pr_debug("%s: total *kvec length: %i\n", __func__, total_length);
+
+	return total_length;
+}
diff --git a/drivers/staging/mausb/drivers/mausb_msapi.h b/drivers/staging/mausb/drivers/mausb_msapi.h
new file mode 100644
index 0000000..7a9c30c
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_msapi.h
@@ -0,0 +1,232 @@
+/* Name:	mausb_msapi.h
+ * Description: This header describes how the media agnostic driver
+ *              interfaces with a media specific driver.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/********************** Initial MS Registration **********************/
+
+/* The MS driver must initially register with the MA driver to make the
+ * inital connection. this is done via a call to mausb_register_ms_driver
+ * (see mausb_hcd.c for details)
+ */
+
+/************************ Packet Send/Recieve ************************/
+
+/* Packets are transferred between the MS and the MA driver via function
+ * calls into each other. When the MA driver has a packet to send out, it
+ * makes a function call into the MS driver with the packet it wishes to
+ * send. Likewise, the MS driver calls into the MA driver if it needs to
+ * pass it a packet.
+ */
+
+/********************** Transfer Pair Add/Remove *********************/
+
+/*
+ * The MA driver establishes a new transfer pair for every independant
+ * connection (ie: one for every independant endpoint, as well as one
+ * for every device). To establish a new connection, the MA driver
+ * calls into the MS driver with an incomplete mausb_transfer_pair.
+ * this incomplete pair includes only the data needed to call into
+ * the MA driver.
+ */
+
+#ifndef __MAUSB_MSAPI_H
+#define __MAUSB_MSAPI_H
+
+#include <linux/uio.h>
+
+/**
+ * Offset in Bytes of location of length field - streaming mediums need to
+ * know where the length field is in a packet so they can determine where
+ * packets begin and end in the stream.
+ */
+#define MAUSB_PKT_LENGTH_OFFSET 2
+ 
+/* the largest number of segments that will ever be in a mausb packet */
+#define MAUSB_PKT_MAX_NR_SEGS 3
+
+/* This is a convenience structure for keeping the number of entries in
+ * the kvec with its pointer.
+ *
+ * @kvec:	The pointer to the ma_pkt kvec or iovec.
+ * @nents:	The number of entires in the ma_pkt kvec or iovec.
+ */
+struct ms_pkt {
+	union {
+		struct kvec kvec[MAUSB_PKT_MAX_NR_SEGS];
+		struct iovec iovec[MAUSB_PKT_MAX_NR_SEGS];
+	};
+	int nents;
+};
+
+
+/**
+ * This struct defines a one way connection for passing packets from one
+ * driver to the other.
+ *
+ * @transfer_packet:	The function call to use when you want to transmit
+ *                   	a packet.
+ * @context:		The context to use in the function when calling the
+ *           		transfer packet.
+ */
+struct mausb_pkt_transfer {
+	int (*transfer_packet)(struct ms_pkt *pkt, void *context);
+	void *context;
+};
+
+int mausb_transfer_packet(struct ms_pkt *pkt,
+	struct mausb_pkt_transfer *transfer);
+
+/**
+ * This struct defines a pair of connections to and from an independant
+ * endpoint or device.
+ *
+ * @to_ma:	The transfer to use when passing a packet to the MA driver
+ *         	from the MS driver.
+ * @to_ms:	The transfer to use when passing a packet to the MS driver
+ *         	from the MA driver.
+ * @pkt_sent: 	Packet completion routine. Called by the MS driver into
+ *            	the MA driver after the packet has been put onto the medium.
+ * @handle: 	A unique identifier for this particualar transfer pair.
+ *          	In our implementation, we use the EP/Device Handle.
+ *		For the management channel, set handle to MAUSB_MGMT_HANDLE.
+ */
+
+#define MAUSB_MGMT_HANDLE 0
+
+struct mausb_transfer_pair {
+	struct mausb_pkt_transfer to_ma;
+	struct mausb_pkt_transfer to_ms;
+	void                    (*pkt_sent)(struct ms_pkt *pkt);
+	unsigned int              handle;
+};
+
+struct urb;
+
+/**
+ * This struct defines all the calls the MA USB-HCD Driver can make
+ * to a media specific driver.
+ *
+ * @add_transfer_pair:	Used to establish a new transfer pair.
+ *       @tx_pair [IN/OUT]:	An incomplete transfer pair. The MA driver
+ *                          	completes the to_ma field and passes it to
+ *				the MA driver. The MS driver fills the
+ *				to_ma field and returns the pointer.
+ * @drop_transfer_pair: Used to remove an existing transfer pair.
+ *       @handle  [IN]:		The unique identifier of the transfer pair
+ *				to remove.
+ * @pkt_destructor: 	Used to destroy a packet that was received from
+ *			the medium. Acts as a hook to allow the medium to
+ *			free any media specific data for a packet.
+ *       @pkt [IN]		The packet the MA driver wishes to free.
+ */
+struct mausb_ms_ops {
+	int  (*add_transfer_pair)(struct mausb_transfer_pair *tx_pair);
+	int  (*drop_transfer_pair)(unsigned long handle, void *context);
+	void (*pkt_destructor)(struct ms_pkt *pkt);
+};
+
+/**
+ * This struct defines all of the media-specific parameters needed by
+ * the MA driver.
+ *
+ * TODO: add spec-defined and implementation-specific variables
+ */
+struct mausb_ms_params {
+
+
+};
+
+/**
+ * This structure includes all of the data needed by the MA driver to
+ * communicate with the Media Specific Driver.
+ *
+ * @ops:	Contains function pointers to all of the functions the
+ *		MA driver will ever need to call.
+ * @params:	Contains all of the media-specific paramaters that the
+ *		MA driver needs.
+ */
+struct mausb_ms_drv {
+	struct mausb_ms_ops *ops;
+	struct mausb_ms_params *params;
+};
+
+/**
+ * This structure includes all of the ways the Media Specific Driver
+ * is capable of calling to the Media Agnostic Driver.
+ *
+ * @device_connect:	Called to indicate that a device has been connected
+ *			and is ready to receive MA packets.
+ * @pkt_dmux:		Used for passing packets into the driver. It will
+ *			parse the packet to determine what endpoint/device
+ *			it belongs to. Used when the medium cannot keep
+ *			data channels seperate.
+ * @pkt_sent:		Used as a notification that a packet has been sent
+ *			out.
+ */
+struct mausb_ma_drv {
+	int (*device_connect)(int);
+	struct mausb_pkt_transfer pkt_dmux;
+	/* TODO: implement pkt_sent indicator */
+	/* void (*pkt_sent)(struct ms_pkt *pkt); */
+};
+
+/* function declarations */
+struct mausb_ma_drv *mausb_register_ms_driver(struct mausb_ms_drv *drv);
+struct mausb_ma_drv *maudc_register_ms_driver(struct mausb_ms_drv *drv);
+void mausb_free_ms_pkt(struct ms_pkt *pkt);
+int mausb_ms_pkt_length(struct ms_pkt *pkt);
+
+#endif
diff --git a/drivers/staging/mausb/drivers/mausb_tcp-device.c b/drivers/staging/mausb/drivers/mausb_tcp-device.c
new file mode 100644
index 0000000..21f90b7
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp-device.c
@@ -0,0 +1,147 @@
+/* Name:	mausb_tcp-device.c
+ * Description: The device side media specific driver to allow media agnostic
+ *               packets over tcp/ip.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "mausb_tcp.h"
+#include "mausb_ioctl.h"
+
+struct mausb_tcp_medium *dev_tcp_medium;
+
+int mausb_tcp_device_thread(void *data)
+{
+	return mausb_tcp_receive_loop(dev_tcp_medium);
+}
+
+int mausb_tcp_device_add_tx_pair(struct mausb_transfer_pair *ma_pair)
+{
+	return mausb_tcp_add_tx_pair(ma_pair, dev_tcp_medium);
+}
+
+static struct mausb_ms_ops ms_ops = {
+	.add_transfer_pair = &mausb_tcp_device_add_tx_pair,
+	.drop_transfer_pair = &mausb_tcp_drop_tx_pair,
+	.pkt_destructor = &mausb_free_ms_pkt
+};
+
+static struct mausb_ms_drv ms_driver = {
+	.ops =  &ms_ops
+};
+
+static int mausb_tcp_device_connect(int on)
+{
+	int ret;
+
+	if (on && dev_tcp_medium->socket == NULL) {
+		ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
+			&dev_tcp_medium->socket);
+
+		if (0 > ret) /* TODO: real errorchecking */
+			return ret;
+
+		do {
+			ret = kernel_connect(dev_tcp_medium->socket,
+				&dev_tcp_medium->addr,
+				sizeof(dev_tcp_medium->addr_in), O_RDWR);
+			pr_debug("%s:kernel_connect returned %i\n",
+				__func__, ret);
+
+			if (0 > ret) {
+				/* poll until we can connect sucessfully */
+				msleep(MAUSB_TCP_DEV_CONNECT_POLL_MS);
+			}
+
+
+		} while (0 > ret);
+
+		/*spawn off a listening thread */
+		dev_tcp_medium->recv_task = kthread_run(mausb_tcp_device_thread,
+			NULL, "mausb_tcp_device_thread");
+	}
+
+	ret = dev_tcp_medium->ma_driver->device_connect(on);
+
+	return ret;
+}
+
+int mausb_tcp_device_init(void)
+{
+	dev_tcp_medium = alloc_init_mausb_tcp_medium(MAUSB_TCP_DEV);
+	if (NULL == dev_tcp_medium)
+		return -ENOMEM;
+
+	dev_tcp_medium->addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	dev_tcp_medium->connect = &mausb_tcp_device_connect;
+
+	dev_tcp_medium->ma_driver = maudc_register_ms_driver(&ms_driver);
+
+
+	return 0;
+}
+module_init(mausb_tcp_device_init);
+
+void mausb_tcp_device_exit(void)
+{
+	free_mausb_tcp_medium(dev_tcp_medium, MAUSB_TCP_DEV);
+}
+module_exit(mausb_tcp_device_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_device");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp-host.c b/drivers/staging/mausb/drivers/mausb_tcp-host.c
new file mode 100644
index 0000000..b186e7c
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp-host.c
@@ -0,0 +1,142 @@
+/* Name:	mausb_tcp-host.c
+ * Description: The host side media specific driver to allow media agnostic
+ *              packets over tcp/ip.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "mausb_tcp.h"
+
+struct mausb_tcp_medium *host_tcp_medium;
+
+int mausb_tcp_host_thread(void *data)
+{
+	return mausb_tcp_receive_loop(host_tcp_medium);
+}
+
+int mausb_tcp_host_add_tx_pair(struct mausb_transfer_pair *ma_pair)
+{
+	return mausb_tcp_add_tx_pair(ma_pair, host_tcp_medium);
+}
+
+static struct mausb_ms_ops ms_ops = {
+	.add_transfer_pair = &mausb_tcp_host_add_tx_pair,
+	.drop_transfer_pair = &mausb_tcp_drop_tx_pair,
+	.pkt_destructor = &mausb_free_ms_pkt
+};
+
+static struct mausb_ms_drv ms_driver = {
+	.ops =  &ms_ops
+};
+
+static int mausb_tcp_host_connect(int on)
+{
+	int ret;
+
+	if (on) {
+		ret = kernel_bind(host_tcp_medium->setup_socket,
+			&host_tcp_medium->addr,
+			sizeof(host_tcp_medium->addr_in));
+
+		ret = kernel_listen(host_tcp_medium->setup_socket,
+			MAUSB_TCP_MAX_NUM_CHANNELS);
+		pr_debug("%s: kernel_listen returned %i\n", __func__, ret);
+
+		ret = kernel_accept(host_tcp_medium->setup_socket,
+				    &host_tcp_medium->socket, 0);
+		pr_debug("%s:kernel_accept returned %i\n", __func__, ret);
+
+		if (0 > ret)
+			return ret;
+
+		if (NULL == host_tcp_medium->recv_task) {
+			host_tcp_medium->recv_task = kthread_run(
+				mausb_tcp_host_thread, NULL,
+				"mausb_tcp_host_thread");
+		}
+	}
+
+	ret = host_tcp_medium->ma_driver->device_connect(on);
+
+	return ret;
+}
+
+int mausb_tcp_host_init(void)
+{
+	host_tcp_medium = alloc_init_mausb_tcp_medium(MAUSB_TCP_HOST);
+	if (NULL == host_tcp_medium)
+		return -ENOMEM;
+
+	host_tcp_medium->addr_in.sin_addr.s_addr = htonl(0);
+
+	host_tcp_medium->connect = &mausb_tcp_host_connect;
+
+	host_tcp_medium->ma_driver = mausb_register_ms_driver(&ms_driver);
+
+	return 0;
+
+}
+module_init(mausb_tcp_host_init);
+
+void mausb_tcp_host_exit(void)
+{
+	free_mausb_tcp_medium(host_tcp_medium, MAUSB_TCP_HOST);
+}
+module_exit(mausb_tcp_host_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_host");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp.c b/drivers/staging/mausb/drivers/mausb_tcp.c
new file mode 100644
index 0000000..a62b77d
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp.c
@@ -0,0 +1,435 @@
+/* Name:	mausb_tcp.c
+ * Description: This is a driver used to connect an MA USB driver to a tcp
+ *              socket.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/uio.h>
+#include <linux/delay.h>
+
+#include "mausb_ioctl.h"
+#include "mausb_tcp.h"
+
+struct mausb_tcp_medium *tcp_medium[MAUSB_TCP_NUM_MODS];
+
+static int gadget_connect_thread(void *data_p)
+{
+	struct mausb_connect_data *data = data_p;
+	int ret;
+
+	pr_debug("%s: Running thread #%i\n", __func__, data->i);
+
+	ret = tcp_medium[data->i]->connect(data->on);
+
+	pr_debug("%s: Thread #%i complete, returing with value %i\n",
+		__func__, data->i, ret);
+
+	kfree(data);
+
+	return ret;
+}
+
+/* for IOCTL */
+int gadget_connection(int on)
+{
+	int i;
+
+	struct mausb_connect_data *data;
+
+	/* make all the calls */
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+
+		if (NULL != tcp_medium[i] &&
+			NULL != tcp_medium[i]->ma_driver) {
+
+			data = kzalloc(sizeof(*data), GFP_KERNEL);
+			if (NULL == data)
+				return -ENOMEM;
+
+			data->task = NULL;
+			data->on = on;
+			data->i = i;
+
+			pr_debug("%s: spawning thread #%i\n", __func__, i);
+
+			data->task = kthread_run(gadget_connect_thread,
+				data, "mausb_connect_thread_%i", i);
+		}
+	}
+
+	return 0;
+}
+
+/* for IOCTL */
+int set_medium_delay(int delay)
+{
+	pr_err("%s: ERROR: cannot set latency of real medium\n", __func__);
+	return -EINVAL;
+}
+
+int set_port_no(int port)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+		if (NULL != tcp_medium[i]) {
+			tcp_medium[i]->addr_in.sin_port = htons(port);
+			ret = port;
+		}
+	}
+
+	return ret;
+}
+
+int set_ip_addr(unsigned long in_addr)
+{
+	int ret = -EINVAL;
+	int i;
+	struct in_addr addr;
+
+	addr.s_addr = htonl(in_addr);
+
+	for (i = 0; i < MAUSB_TCP_NUM_MODS; ++i) {
+		if (NULL != tcp_medium[i]) {
+			tcp_medium[i]->addr_in.sin_addr = addr;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+int set_mac_addr(unsigned char mac_addr[ETH_ALEN])
+{
+	pr_err("%s: ERROR: cannot set mac address for TCP\n", __func__);
+	return -EINVAL;
+}
+
+inline void *mausb_tcp_to_context(struct mausb_tcp_medium *medium)
+{
+	return (void *) medium;
+}
+EXPORT_SYMBOL(mausb_tcp_to_context);
+
+inline struct mausb_tcp_medium *mausb_context_to_tcp(void *context)
+{
+	return (struct mausb_tcp_medium *) context;
+}
+EXPORT_SYMBOL(mausb_context_to_tcp);
+
+static void mausb_tcp_init_msg(struct msghdr *msg)
+{
+	msg->msg_name = NULL;
+	msg->msg_namelen = 0;
+	msg->msg_control = NULL;
+	msg->msg_controllen = 0;
+	msg->msg_flags = 0;
+}
+
+static int mausb_tcp_enqueue(struct ms_pkt *pkt, void *context)
+{
+	struct msghdr msg;
+	struct mausb_tcp_medium *tcp_medium;
+	int total_length = 0;
+	int ret = 0;
+	int i;
+
+	mausb_tcp_init_msg(&msg);
+
+	if (NULL == context) {
+		pr_err("%s: ERROR: null context\n", __func__);
+		return -EINVAL;
+	}
+	tcp_medium = mausb_context_to_tcp(context);
+
+	if (NULL == tcp_medium->socket) {
+		pr_err("%s: ERROR: no socket for packet\n", __func__);
+		return -ENOTCONN;
+	}
+
+	for (i = 0; i < pkt->nents; ++i) {
+		total_length += pkt->kvec[i].iov_len;
+	}
+
+	ret = kernel_sendmsg(tcp_medium->socket, &msg, pkt->kvec, pkt->nents,
+		total_length);
+
+	pr_debug("%s: sent %i bytes\n", __func__, ret);
+
+	/*
+	 * TODO: implement completion (pkt_sent) callback
+	 * if (NULL != tcp_medium->tx_pair.pkt_sent && 0 < ret)
+	 * tcp_pair->tx_pair.pkt_sent(pkt);
+	 */
+
+	return ret;
+}
+
+static int mausb_tcp_receive_packet(struct mausb_tcp_medium *tcp_medium,
+		struct msghdr *msg, struct ms_pkt *pkt)
+{
+	struct kvec kvec;
+	int data_rcvd;
+	int total_rcvd = 0;
+	__u16 length;
+	void *buf;
+
+	buf = kmalloc(MAUSB_TCP_BUF_SIZE, GFP_KERNEL);
+	if (NULL == buf)
+		return -ENOMEM;
+
+	kvec.iov_base = buf;
+	kvec.iov_len = MAUSB_TCP_BUF_SIZE;
+
+	/* receive the first DWORD to determine length */
+	data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec, 1,
+					sizeof(__u32), MSG_DONTWAIT);
+
+	while (data_rcvd == -EAGAIN && !kthread_should_stop()) {
+		/* sleep to prevent excessive polling */
+		msleep(10);
+
+		/* receive the first DWORD to determine length */
+		data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec,
+				1, sizeof(__u32), MSG_DONTWAIT);
+	}
+
+	if (0 > data_rcvd) {
+		pr_err("%s: ERROR: Could not read packet length"
+			" (error #%i)\n", __func__, data_rcvd);
+		kfree(buf);
+		return data_rcvd;
+	}
+
+	/* the data is invalid */
+	if (sizeof(__u32) > data_rcvd) {
+		pr_err("%s: ERROR: did not read enough data to get length"
+			" (received %i bytes)\n", __func__, data_rcvd);
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	length = le16_to_cpu(*((__le16 *)(buf + MAUSB_PKT_LENGTH_OFFSET)));
+	total_rcvd += data_rcvd;
+
+	/* make sure length is valid */
+	if (length < sizeof(__u32)) {
+		pr_err("%s: ERROR: length field too small (%u)\n",
+			 __func__, length);
+		kfree(buf);
+		return -EINVAL;
+	}
+
+	/* receive the remainder of the packet */
+	while (total_rcvd < length && total_rcvd >= 0 &&
+		!kthread_should_stop()) {
+
+		data_rcvd = kernel_recvmsg(tcp_medium->socket, msg, &kvec,
+			1, length - total_rcvd, 0);
+
+		if (0 < data_rcvd) {
+			total_rcvd += data_rcvd;
+
+		} else if (0 > data_rcvd) {
+			pr_err("%s: ERROR: while receiving packet "
+			"(err #%i)\n", __func__, data_rcvd);
+			kfree(buf);
+			return data_rcvd;
+		}
+	}
+
+	if (total_rcvd != length) {
+		pr_warn("%s: Warning: did not receive enough data "
+			"(length:%u, received:%i)\n", __func__,
+			length, total_rcvd);
+	}
+
+
+	pkt->nents = 1;
+	pkt->kvec[0].iov_base = buf;
+	pkt->kvec[0].iov_len = total_rcvd;
+
+	return total_rcvd;
+}
+
+int mausb_tcp_receive_loop(struct mausb_tcp_medium *tcp_medium)
+{
+	struct msghdr msg;
+	struct ms_pkt *pkt;
+	int data_rcvd = 0;
+
+	mausb_tcp_init_msg(&msg);
+
+	while (!kthread_should_stop()) {
+
+		pkt = kzalloc(sizeof(struct ms_pkt), GFP_KERNEL);
+
+		pr_debug("%s: preparing to receive data\n", __func__);
+
+		data_rcvd = mausb_tcp_receive_packet(tcp_medium, &msg, pkt);
+
+		if (0 >= data_rcvd) {
+			pr_err("%s: received no data (err %i)\n", __func__,
+				data_rcvd);
+
+			sock_release(tcp_medium->socket);
+			return data_rcvd;
+
+		} else {
+			pr_debug("%s: received %i bytes\n", __func__,
+				data_rcvd);
+		}
+
+		if (data_rcvd > 0) {
+			mausb_transfer_packet(pkt,
+				&tcp_medium->ma_driver->pkt_dmux);
+		}
+
+		data_rcvd = 0;
+	}
+
+	sock_release(tcp_medium->socket);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_receive_loop);
+
+int mausb_tcp_add_tx_pair(struct mausb_transfer_pair *ma_pair,
+	struct mausb_tcp_medium *medium)
+{
+	ma_pair->to_ms.transfer_packet = &mausb_tcp_enqueue;
+	ma_pair->to_ms.context = mausb_tcp_to_context(medium);
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_add_tx_pair);
+
+int mausb_tcp_drop_tx_pair(unsigned long handle, void *context)
+{
+	/* TODO: something here */
+
+	return 0;
+}
+EXPORT_SYMBOL(mausb_tcp_drop_tx_pair);
+
+/**
+ * initialization function
+ */
+struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
+	enum mausb_tcp_module_type type)
+{
+	struct mausb_tcp_medium *medium;
+	int ret;
+
+	medium = kzalloc(sizeof(struct mausb_tcp_medium), GFP_KERNEL);
+	if (NULL == medium)
+		return NULL;
+
+	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
+		&medium->setup_socket);
+
+	medium->addr_in.sin_family = AF_INET;
+	medium->addr_in.sin_port = htons(MAUSB_TCP_PORT_HOST);
+
+	spin_lock_init(&medium->lock);
+
+	tcp_medium[type] = medium;
+
+	return medium;
+}
+EXPORT_SYMBOL(alloc_init_mausb_tcp_medium);
+
+/**
+ * exit function
+ */
+void free_mausb_tcp_medium(struct mausb_tcp_medium *medium,
+	enum mausb_tcp_module_type type)
+{
+	if (medium->recv_task)
+		kthread_stop(medium->recv_task);
+
+	if (medium->setup_socket)
+		sock_release(medium->setup_socket);
+
+	tcp_medium[type] = NULL;
+
+	kfree(medium);
+}
+EXPORT_SYMBOL(free_mausb_tcp_medium);
+
+int mausb_tcp_core_init(void)
+{
+	int ret;
+
+	ret = reg_chrdev();
+	if (0 > ret) {
+		pr_err("%s: reg_chrdev() failed\n", __func__);
+	}
+
+	return ret;
+
+}
+module_init(mausb_tcp_core_init);
+
+void mausb_tcp_core_exit(void)
+{
+	unreg_chrdev();
+}
+module_exit(mausb_tcp_core_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_tcp_core");
diff --git a/drivers/staging/mausb/drivers/mausb_tcp.h b/drivers/staging/mausb/drivers/mausb_tcp.h
new file mode 100644
index 0000000..879a7fa
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tcp.h
@@ -0,0 +1,129 @@
+/* Name: mausb_tcp.h
+ * Description: header file for mausb_tcp.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_TCP_H
+#define __MAUSB_TCP_H
+
+#include <linux/net.h>
+#include <linux/kthread.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+
+#include "mausb_msapi.h"
+
+#define MAUSB_TCP_PORT_HOST 9001
+
+/* used to determine how many times we have to listen */
+#define MAUSB_TCP_MAX_NUM_CHANNELS 1
+
+/* how often the device should poll while connecting */
+#define MAUSB_TCP_DEV_CONNECT_POLL_MS 100
+
+/* how often to poll the port to check for a new message */
+#define MAUSB_TCP_POLL_PORT_MS 5
+
+#define MAUSB_TCP_BUF_SIZE PAGE_SIZE
+
+#define MAUSB_MAX_NAME_LEN 50
+
+#define MAUSB_TCP_RECV_POLL 1 /* in ms */
+
+#define MAUSB_DWORD_LENGTH 4 /* DWORD = 4 bytes */
+
+enum mausb_tcp_module_type {
+	MAUSB_TCP_DEV = 0,
+	MAUSB_TCP_HOST,
+	MAUSB_TCP_NUM_MODS
+};
+
+struct mausb_tcp_medium {
+	struct socket *setup_socket;
+	union {
+		struct sockaddr_in addr_in;
+		struct sockaddr addr;
+	};
+	spinlock_t lock;
+	struct mausb_ma_drv *ma_driver;
+
+	struct socket *socket;
+	struct task_struct *recv_task;
+
+	/* function call for when a device connect/disconnect is made */
+	int (*connect)(int on);
+};
+
+/* Used so that host and device side connect functions can run simultaniously.
+ * See gadget_connection() & gadget_connect_thread() for details. */
+struct mausb_connect_data {
+	struct task_struct *task;
+	int i;
+	int on;
+};
+
+/* function declarations */
+struct mausb_tcp_medium *mausb_tcp_get_medium(void);
+void *mausb_tcp_to_context(struct mausb_tcp_medium *medium);
+struct mausb_tcp_medium *mausb_context_to_tcp(void *context);
+int mausb_tcp_receive_loop(struct mausb_tcp_medium *medium);
+int mausb_tcp_add_tx_pair(struct mausb_transfer_pair *ma_pair,
+		struct mausb_tcp_medium *medium);
+int mausb_tcp_drop_tx_pair(unsigned long handle, void *context);
+struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
+		enum mausb_tcp_module_type type);
+void free_mausb_tcp_medium(struct mausb_tcp_medium *medium,
+		enum mausb_tcp_module_type type);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 06/10] added media agnostic (MA) UDC
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (3 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

This is where we implement the behavior of a USB device controller for
the MA USB device-side driver. The MA UDC interfaces with a gadget driver
and appears to the driver as a regular UDC. However, instead of sending
USB packets over a wired USB bus, the MA UDC hands MA USB packets off to
a media specific layer for transport.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_udc.c | 1486 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_udc.h |  147 +++
 2 files changed, 1633 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_udc.h

diff --git a/drivers/staging/mausb/drivers/mausb_udc.c b/drivers/staging/mausb/drivers/mausb_udc.c
new file mode 100644
index 0000000..af00786
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_udc.c
@@ -0,0 +1,1486 @@
+/* name:	mausb_udc.c
+ * description: Implements a USB device controller(UDC) for interfacing with
+ *		gadget drivers. The gadget driver uses this interface to return
+ *		descriptors and to implement configuration and data transfer
+ *		protocols with the pHCD. The UDC also allocates and initializes
+ *		endpoints to support gadget/pHCD interfacing.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.o.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/gadget.h>
+#include <linux/device.h>
+#include <linux/usb/composite.h>
+#include <linux/spinlock.h>
+
+#include "mausb_udc.h"
+#include "mausb_mgmt.h"
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+#include "mausb_tx.h"
+
+static const char	 ep0[] = "ep0";
+static const char *const ep_name[] = {ep0, "ep1", "ep2"};
+
+static struct platform_device udc_pdev;
+
+void udc_dev_release(struct device *dev)
+{
+	/* free any dynamically allocated structures here */
+}
+
+static inline struct mausb_udc *gadget_to_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct mausb_udc, gadget);
+}
+
+static inline struct mausb_udc *gadget_dev_to_mausb_udc(struct device *dev)
+{
+	return container_of(dev, struct mausb_udc, gadget.dev);
+}
+
+static inline struct mausb_request *usb_req_to_mausb_req(
+		struct usb_request *req)
+{
+	return container_of(req, struct mausb_request, req);
+}
+
+static inline struct mausb_udc *mausb_ma_dev_to_udc(struct ma_dev *ma_dev)
+{
+	return container_of(ma_dev, struct mausb_udc, ma_dev);
+}
+
+/*
+ * forward declarations
+ */
+static int set_or_clear_gadget_feature(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc, int set);
+static int get_gadget_status(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc);
+
+/**
+ * Finds a matching endpoint for a given address.
+ */
+static struct usb_ep *get_ep(struct mausb_udc *udc, u8 address)
+{
+	int			i;
+	struct usb_ep		*ep;
+
+	/* address is 0 (ignore direction bit flag) */
+	if ((address & ~USB_DIR_IN) == 0)
+		return &udc->usb_ep[0].dev_ep;
+
+	/* otherwise look for match */
+	for (i = 1; i < MAUDC_MAX_NUM_EP; i++) {
+
+		ep = &udc->usb_ep[i].dev_ep;
+
+		if (ep->address == address)
+			return ep;
+	}
+
+	maudc_dbg(udc, "%s: no endpoint found for address 0x%x\n",
+		__func__, address);
+
+	return NULL;
+}
+
+/**
+ * Called by gadget driver to enable endpoint.
+ */
+static int mausb_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep		*ma_ep = mausb_find_ep_by_desc(desc,
+						udc->mausb_dev);
+
+	maudc_dbg(udc, "%s: enabling gadget endpoint %s\n",
+		__func__, ep->name);
+
+	/* ep0 is control endpoint, don't try and configure it */
+	if (ep->name == ep0) {
+		maudc_err(udc, "%s: cannot configure ep0\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Get maximum packet size from descriptor and set for ep.
+	 * Bits 0->10 of wMaxPacketSize = maximum packet size for HS and
+	 * FS devices maximum packet size for SS devices = 1024.
+	 */
+	ep->maxpacket = EP_MAX_PACKET;
+
+	if (NULL != ma_ep)
+		mausb_link_ma_ep_to_usb_ep(ma_ep, ep);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to disable endpoint.
+ */
+static int mausb_ep_disable(struct usb_ep *ep)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (!ep) {
+		maudc_dbg(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	maudc_dbg(udc, "%s: disabling gadget endpoint %s\n",
+		__func__, ep->name);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to allocate a request packet.
+ */
+static struct usb_request *mausb_ep_alloc_request(struct usb_ep *ep,
+		gfp_t mem_flags)
+{
+	struct mausb_request *req;
+
+	if (!ep)
+		return NULL;
+
+	req = kzalloc(sizeof(*req), mem_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->usb_req_list);
+
+	return &req->req;
+}
+
+/**
+ * Called by gadget driver to free a request packet.
+ */
+static void mausb_ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mausb_request *mreq;
+
+	if (!ep || !req)
+		return;
+
+	mreq = usb_req_to_mausb_req(req);
+	kfree(mreq);
+}
+
+/**
+ * Called by gadget driver to queue a request.
+ */
+static int mausb_ep_queue(struct usb_ep *ep, struct usb_request *req,
+		gfp_t mem_flags)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_request		*ma_req;
+	struct mausb_gadget_ep		*gadget_ep;
+
+	if (!ep) {
+		maudc_err(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!req) {
+		maudc_err(udc, "%s: no USB request\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_req = usb_req_to_mausb_req(req);
+	gadget_ep = usb_ep_to_mausb_gadget_ep(ep);
+
+	req->status = -EINPROGRESS;
+	req->actual = 0;
+
+	maudc_dbg(udc, "%s: queueing request to ep %i at 0x%p with data at "
+		"0x%p\n", __func__, usb_endpoint_num(ep->desc), ep, req->buf);
+
+	list_add_tail(&ma_req->usb_req_list, &gadget_ep->usb_req_list);
+
+	return 0;
+}
+
+/**
+ * Called by gadget driver to dequeue a request.
+ */
+static int mausb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_request		*ma_req;
+
+	if (!ep) {
+		maudc_err(udc, "%s: no endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!req) {
+		maudc_err(udc, "%s: no USB request\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_req = usb_req_to_mausb_req(req);
+
+	list_del(&ma_req->usb_req_list);
+
+	maudc_dbg(udc, "%s: dequeueing request\n", __func__);
+
+	return 0;
+}
+
+/**
+ * Halts or clears a halt of an endpoint.
+ */
+static int mausb_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct mausb_udc 	*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(ep, udc->mausb_dev);
+
+	if (NULL == ma_ep) {
+		maudc_err(udc, "%s: no MA USB endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	/* probably don't want to halt default control ep */
+	if (ma_ep->dev_ep->name == ep0) {
+		maudc_err(udc, "%s: cannot halt ep0!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (value) {
+		maudc_dbg(udc, "%s: halting ep\n", __func__);
+		ma_ep->halted = 1;
+	}
+
+	else {
+		maudc_dbg(udc, "%s: clearing ep halt\n", __func__);
+		ma_ep->halted = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * Wedges an endpoint; wedge causes request to clear halt from host to be
+ * ignored.
+ */
+static int mausb_ep_set_wedge(struct usb_ep *ep)
+{
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(ep, udc->mausb_dev);
+
+	if (NULL == ma_ep) {
+		maudc_err(udc, "%s: no MA USB endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	/* wedging default control ep is probably bad */
+	if (ma_ep->dev_ep->name == ep0) {
+		maudc_dbg(udc, "%s: cannot wedge ep0\n", __func__);
+		return -EINVAL;
+	}
+
+	ma_ep->halted = 1;
+	ma_ep->wedged = 1;
+
+	return 0;
+}
+
+static struct usb_ep_ops mausb_ep_ops = {
+	.enable = mausb_ep_enable,
+	.disable = mausb_ep_disable,
+	.alloc_request = mausb_ep_alloc_request,
+	.free_request = mausb_ep_free_request,
+	.queue = mausb_ep_queue,
+	.dequeue = mausb_ep_dequeue,
+	.set_halt = mausb_ep_set_halt,
+	.set_wedge = mausb_ep_set_wedge
+};
+
+/*---------------------- transfer operations ------------------------------*/
+
+/**
+ * Handles control requests from usb core. Returns 0 if request is fully
+ * handled, otherwise returns the length of the transfer
+ */
+static int handle_ma_control_request(struct mausb_host_ep *ep,
+		struct usb_ctrlrequest *ctrlreq)
+{
+	int			ret = 0;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+
+	if (!ctrlreq) {
+		maudc_err(udc, "%s: no control request\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * UDC handles set/clear feature, get status, and set address
+	 * requests, anything else is passed to gadget driver.
+	 */
+	switch (ctrlreq->bRequest) {
+	case USB_REQ_CLEAR_FEATURE:
+		maudc_dbg(udc, "USB_REQ: clearing feature\n");
+		ret = set_or_clear_gadget_feature(ctrlreq, udc, 0);
+		break;
+
+	case USB_REQ_GET_STATUS:
+		maudc_dbg(udc, "USB_REQ: getting status\n");
+		ret = get_gadget_status(ctrlreq, udc);
+		break;
+
+	case USB_REQ_SET_FEATURE:
+		maudc_dbg(udc, "USB_REQ: setting feature\n");
+		ret = set_or_clear_gadget_feature(ctrlreq, udc, 1);
+		break;
+
+	default: /* pass the request to the gadget driver */
+		maudc_dbg(udc, "USB_REQ: forwarding REQ #%i to gadget driver\n",
+				ctrlreq->bRequest);
+		if (NULL != udc->driver)
+			ret = udc->driver->setup(&udc->gadget, ctrlreq);
+		else
+			maudc_err(udc, "gadget driver not found\n");
+
+		if (ret >= 0)
+			ret = ctrlreq->wLength;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Transfers contents of request and endpoint buffers.
+ */
+int do_ma_transfer(struct mausb_host_ep *ep, struct mausb_pkt *tx_req,
+		bool dir_in)
+{
+	int				i = 0;
+	int				out_copy_length = 0;
+	int				ret, host_len, device_len;
+	int				status = -EINPROGRESS;
+	int				length = 0;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+	struct mausb_request		*req, *next;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	void				*epbuf, *rbuf;
+
+	/* look for setup data */
+	if (tx_req->setup)
+		ret = handle_ma_control_request(ep, tx_req->setup);
+
+	if (NULL == ep->usb_req_list)
+		return -ENOTCONN;
+
+	if (list_empty(ep->usb_req_list) && !in_interrupt()) {
+		maudc_dbg(udc, "wait gadget function driver submit request\n");
+		while (list_empty(ep->usb_req_list) &&
+		       i <= MAUSB_GADGET_TIMEOUT) {
+			msleep(1);
+			i++;
+		}
+	}
+	if (i > MAUSB_GADGET_TIMEOUT) {
+		maudc_dbg(udc, "Wait gadget request time out\n");
+		return -ETIMEDOUT;
+	}
+
+ loop_request_queue:
+	/* take care of each request in request queue */
+	list_for_each_entry_safe(req, next, ep->usb_req_list, usb_req_list) {
+
+		if (dir_in)
+			host_len = tx_state->rem_size - ep->actual_length;
+		else
+			host_len = tx_req->buffer_length - out_copy_length;
+		device_len = req->req.length - req->req.actual;
+		length = min(host_len, device_len);
+
+		/* there is something to transfer so do transfer */
+		if (length > 0) {
+
+			rbuf = req->req.buf + req->req.actual;
+
+			/*
+			 * If IN transfer, copy req buffer contents into
+			 * ep buffer. Vice versa for OUT transfer.
+			 */
+			if (dir_in) {
+				epbuf = ep->buffer + ep->actual_length;
+				if (epbuf)
+					memcpy(epbuf, rbuf, length);
+				else
+					maudc_err(udc, "%s: no ep buffer\n",
+						__func__);
+			} else {
+				/*
+				 * For bulk OUT, we can't use ep->actual_length
+				 * as indicator because ep->buffer for every
+				 * transfer request is only "rx_buf_size" bytes
+				 * length.
+				 */
+				epbuf = ep->buffer + out_copy_length;
+				memcpy(rbuf, epbuf, length);
+				out_copy_length += length;
+			}
+			ep->actual_length += length;
+			req->req.actual += length;
+		}
+		/* zero length packet ends a read */
+		else {
+			req->req.status = 0;
+			status = 0;
+		}
+
+		/*
+		 * A transfer usually ends when buffer contents are completely
+		 * transferred. But, look out for for the zero packet transfer
+		 * flag. If flag is set, bulk OUT transfers need to wait for
+		 * zero length packet (short packet) for completion.
+		 */
+		if ((req->req.length == req->req.actual) ||
+		    /* bulk IN short packet */
+		    (dir_in && (req->req.actual % ep->dev_ep->maxpacket)) ||
+		    /* bulk OUT transfer all data requested by host urb*/
+		    (!dir_in && ep->active_transfer->transfer_size
+		     == ep->actual_length) ||
+		    /* bulk OUT last request */
+		    (!dir_in && req->req.zero)) {
+			req->req.status = 0;
+			/* device completion */
+			list_del_init(&req->usb_req_list);
+			req->req.complete(ep->dev_ep, &req->req);
+		}
+
+		if (tx_state->rem_size == 0)
+			status = 0;
+
+		/*
+		 * Host completion - end when nothing left to read/write,
+		 * otherwise keep going through queue.
+		 */
+		if (status != -EINPROGRESS)
+			break;
+		/* bulk IN/OUT transfers last request serves for one host urb */
+		if (tx_state->rem_size == req->req.actual) {
+			maudc_dbg(udc, "bulk IN/OUT last request return\n");
+			break;
+		}
+		/* bulk IN short packet */
+		if (dir_in && (req->req.actual % ep->dev_ep->maxpacket)) {
+			maudc_dbg(udc, "bulk IN short packet return\n");
+			break;
+		}
+		/*
+		 * Bulk OUT transfer contains multiple bulk OUT MA requests.
+		 * So for bulk out MA request just return to serve subsequent
+		 * bulk out MA request.
+		 */
+		if (!dir_in && host_len == length) {
+			maudc_dbg(udc, "normal bulk OUT MA request return\n");
+			break;
+		}
+		/*
+		 * Gadget driver should transfer more data to
+		 * serve bulk IN transfer, then wait for more requests.
+		 */
+		if (dir_in && (req->req.actual % ep->dev_ep->maxpacket == 0) &&
+		    (tx_state->rem_size - ep->actual_length > 0)
+		    && !req->req.zero) {
+			if (list_empty(ep->usb_req_list)) {
+				maudc_dbg(udc, "bulk IN: gadget request queue"
+					" is empty - waiting . . .\n");
+				while (list_empty(ep->usb_req_list))
+					msleep(1);
+			}
+			goto loop_request_queue;
+		}
+		/*
+		 * Doesn't copy all data in MA USB bulk OUT request.
+		 * Wait for additional gadget requests
+		 * to serve this MA USB bulk OUT request.
+		 */
+		if (!dir_in && (host_len > length)) {
+			if (list_empty(ep->usb_req_list)) {
+				maudc_dbg(udc, "bulk OUT: gadget request"
+					" is queue empty - waiting . . .\n");
+				while (list_empty(ep->usb_req_list))
+					msleep(1);
+			}
+			goto loop_request_queue;
+		}
+	}
+
+	return ep->actual_length;
+}
+
+
+/*------------------------- gadget operations -------------------------*/
+
+/**
+ * Handles control request to get device status.
+ */
+static int get_gadget_status(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc)
+{
+	int			ret = 0;
+	char			*buf;
+	unsigned int		address = le16_to_cpu(ctrlreq->wIndex);
+	struct usb_ep		*usb_ep = get_ep(udc, address);
+	struct mausb_host_ep	*ma_ep = mausb_find_ep_dev(usb_ep,
+					udc->mausb_dev);
+
+	if (!ma_ep) {
+		maudc_err(udc, "%s: cannot find endpoint\n", __func__);
+		return -EINVAL;
+	}
+
+	buf = (char *)ma_ep->buffer;
+
+	maudc_dbg(udc, "%s: responding to request type %i\n",
+			__func__, ctrlreq->bRequestType);
+
+	/* requesting device status */
+	switch (ctrlreq->bRequestType) {
+	case DEV_IN_REQ:
+		buf[0] = udc->dev_status;
+		ma_ep->actual_length = 1;
+		break;
+
+	/* requesting an endpoint status */
+	case EP_IN_REQ:
+		buf[0] = ma_ep->halted;
+		ma_ep->actual_length = 1;
+		break;
+
+	/* requesting interface status */
+	case INTF_IN_REQ:
+		buf[0] = 0;
+		break;
+
+	default:
+		maudc_dbg(udc, "%s: invalid request type %i\n",
+			__func__, ctrlreq->bRequestType);
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Handles control request to set a gadget device feature.
+ */
+static int set_or_clear_gadget_feature(struct usb_ctrlrequest *ctrlreq,
+		struct mausb_udc *udc, int set)
+{
+	int			ret = 0;
+	unsigned int		address = le16_to_cpu(ctrlreq->wIndex);
+	struct usb_ep		*usb_ep = get_ep(udc, address);
+	struct mausb_host_ep	*ma_ep  = mausb_find_ep_dev(usb_ep,
+					udc->mausb_dev);
+
+	if (ctrlreq->bRequestType == EP_REQ) {
+
+		if (!ma_ep)
+			ret = -EINVAL;
+		else if (ma_ep->dev_ep->name == udc->gadget.ep0->name) {
+			maudc_err(udc, "%s: cannot halt ep0!\n", __func__);
+			ret = -EINVAL;
+		} else {
+			ma_ep->halted = set;
+			maudc_dbg(udc, "%s: %s halt %s\n", __func__,
+				ma_ep->dev_ep->name, set ? "set" : "cleared");
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Handles incoming management packets. Used to pass an MA USB management
+ * packet to the device.
+ */
+static int maudc_transfer_mgmt_packet(struct ms_pkt *ms_pkt, void *context)
+{
+	int			ret;
+	struct mausb_pkt	*pkt;
+	struct mausb_udc	*udc  = platform_get_drvdata(&udc_pdev);
+	struct mausb_mgmt	*mgmt;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		maudc_err(udc, "%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	mgmt = (struct mausb_mgmt *) context;
+
+	pkt = mausb_pkt_from_ms_pkt(ms_pkt,
+			udc->ma_dev.ms_driver->ops->pkt_destructor, GFP_ATOMIC);
+
+	maudc_dbg(udc, "%s: received %s packet\n", __func__,
+		mausb_type_to_string(pkt->common->pkt_type));
+
+	ret = mausb_rx_mgmt(pkt, mgmt);
+
+	return ret;
+}
+
+/**
+ * Suspends gadget..Called when a MAUSBDeviceSleepReq management packet is
+ * received.
+ */
+static void mausb_device_suspend(void)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver)
+		udc->driver->suspend(&udc->gadget);
+}
+
+/**
+ * Resumes gadget. Called by mausb_bus_resume in hcd to resume a connected
+ * device.
+ */
+static void mausb_device_resume(void)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver)
+		udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * Manages USB device connection to host. Called for connect and disconnect
+ * events.
+ */
+static int mausb_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct mausb_udc *udc = gadget_to_udc(gadget);
+
+	udc->usb_ep[0].dev_ep.maxpacket = 64;
+	udc->gadget.speed = udc->driver->max_speed;
+	udc->pullup = is_on;
+
+	return 0;
+}
+
+/**
+ * Assigns an MA USB ep handle to the given endpoint.
+ */
+static void maudc_assign_ep_handle(struct mausb_host_ep *ma_ep,
+		struct usb_endpoint_descriptor *ep_des)
+{
+	struct mausb_ep_handle *handle = &ma_ep->ep_handle;
+
+	handle->dir = usb_endpoint_dir_in(ep_des) ? 1 : 0;
+	handle->ep_num = usb_endpoint_num(ep_des);
+	handle->dev_addr = MAUDC_DEV_ADDR;
+	handle->bus_num = MAUSB_VIRTUAL_BUS_NUM;
+
+	ma_ep->ep_handle_state = MAUSB_EP_HANDLE_ACTIVE;
+}
+
+/**
+ * Adds a media-agnostic endpoint datastructure to the UDC for the given
+ * endpoint.
+ */
+static int maudc_add_ma_ep(struct usb_endpoint_descriptor *ep_des,
+		struct mausb_dev *mausb_dev, struct mausb_host_ep **mausb_ep)
+{
+	int			ret = -EINVAL;
+	struct mausb_host_ep	*ma_ep;
+	struct mausb_ms_drv	*drv = mausb_dev->ma_dev->ms_driver;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	struct usb_ep		*usb_ep = get_ep(udc, ep_des->bEndpointAddress);
+	unsigned long		irq_flags;
+	int (*transfer_pkt)(struct ms_pkt *pkt, void *context);
+
+	if (USB_ENDPOINT_XFER_CONTROL == usb_endpoint_type(ep_des)) {
+
+		maudc_dbg(udc, "%s: adding control endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_control;
+
+	} else if (usb_endpoint_dir_in(ep_des)) {
+		maudc_dbg(udc, "%s: adding IN endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_IN;
+
+	} else if (usb_endpoint_dir_out(ep_des)) {
+		maudc_dbg(udc, "%s: adding OUT endpoint %i...\n",
+			__func__, usb_endpoint_num(ep_des));
+		transfer_pkt = &receive_ma_packet_OUT;
+
+	} else {
+		maudc_dbg(udc, "%s: unknown endpoint type\n", __func__);
+		return -EINVAL;
+	}
+
+	mausb_internal_add_ep(mausb_dev, NULL, usb_ep, &ma_ep,
+		&device_transfer_timeout, GFP_ATOMIC);
+
+	if (NULL == ma_ep)
+		return -ENOMEM;
+
+	maudc_dbg(udc, "%s: added endpoint at 0x%p\n", __func__, ma_ep);
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	maudc_assign_ep_handle(ma_ep, ep_des);
+	ret = mausb_add_data_channel(drv, ma_ep, transfer_pkt);
+
+	ma_ep->gadget = mausb_dev->gadget;
+
+	/*
+	 * Note: The UDC uses a single MA URB to track the transfer
+	 * State variables for the active transfer.
+	 */
+	ma_ep->active_transfer = mausb_alloc_maurb(ma_ep, GFP_ATOMIC);
+
+	if (NULL != mausb_ep)
+		*mausb_ep = ma_ep;
+
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+	return ret;
+}
+
+/**
+ * Registers a media specific driver with the media agnostic driver.
+ */
+struct mausb_ma_drv *maudc_register_ms_driver(struct mausb_ms_drv *drv)
+{
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&udc->udc_lock, irq_flags);
+	udc->ma_dev.ms_driver = drv;
+	spin_unlock_irqrestore(&udc->udc_lock, irq_flags);
+
+	/* open the management channel */
+	maudc_dbg(udc, "%s: adding Managment channel...\n", __func__);
+	mausb_add_mgmt_channel(&udc->ma_dev.mgmt, drv,
+		&maudc_transfer_mgmt_packet, &mausb_mgmt_pkt_sent);
+
+	return &udc->ma_dev.ma_drv;
+}
+EXPORT_SYMBOL(maudc_register_ms_driver);
+
+int check_for_device(int dont_use)
+{
+	struct mausb_udc *udc = platform_get_drvdata(&udc_pdev);
+
+	if (udc->driver != NULL)
+		return 1;
+
+	return 0;
+}
+
+static int mausb_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct mausb_udc	*udc = gadget_to_udc(gadget);
+
+	maudc_dbg(udc, "%s: binding gadget '%s' driver\n",
+		__func__, driver->driver.name);
+
+	udc->driver = driver;
+
+	return 0;
+}
+
+static int mausb_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	struct mausb_udc	*udc = gadget_to_udc(gadget);
+
+	maudc_dbg(udc, "%s: stopping udc\n", __func__);
+
+	udc->driver = NULL;
+
+	return 0;
+}
+
+/**
+ * API to UDC operations that do not involve endpoints or i/o.
+ */
+static struct usb_gadget_ops mudc_ops = {
+	.pullup = &mausb_udc_pullup,
+	.udc_start = &mausb_udc_start,
+	.udc_stop = &mausb_udc_stop
+};
+
+/**
+ * Appends a Capabilities Descriptor to the end of a CapResp packet.
+ *
+ * @resp:	     CapResp to that will carry descriptor.
+ * @type:	     Descriptor type to add.
+ *		     Note: make sure to use values from MA USB Spec, Table 14.
+ * @offset:          Total length of other Device Capability Descriptors
+ *		     in resp.
+ *
+ * Returns length of added descriptor.
+ */
+static int add_cap_desc(struct mausb_mgmt_pkt *resp, int type, int offset)
+{
+	int			ret = 0;
+	int			ttl_offset;
+	struct			mausb_dev_cap_desc *desc;
+	struct mausb_udc	*udc = platform_get_drvdata(&udc_pdev);
+
+	ttl_offset = MAUSB_PKT_HEADER_SIZE +
+			sizeof(struct mausb_CapResp_flds) + offset;
+	desc = cap_desc_ptr_increment(resp, ttl_offset);
+
+	switch (type) {
+	case MAUSB_DEV_CAP_SPEED:
+		desc->length = MAUSB_DEV_CAP_SPEED_LENGTH;
+		desc->cap_type = MAUSB_DEV_CAP_SPEED;
+		desc->speed.speed = MAUSB_DEV_CAP_SPEED_SUPER;
+		/* TODO: assign speed fields meaningful values */
+		desc->speed.lse = 1;
+		desc->speed.st = 2;
+		desc->speed.lane_count = 3;
+		desc->speed.link_protocol = 3;
+		desc->speed.lsm = 234;
+		ret = desc->length;
+		break;
+	case MAUSB_DEV_CAP_POUT:
+		break;
+	case MAUSB_DEV_CAP_ISO:
+		break;
+	case MAUSB_DEV_CAP_SYNC:
+		break;
+	case MAUSB_DEV_CAP_CONT_ID:
+		break;
+	case MAUSB_DEV_CAP_LINK_SLEEP:
+		desc->length = MAUSB_DEV_CAP_LINK_SLEEP_LENGTH;
+		desc->cap_type = MAUSB_DEV_CAP_LINK_SLEEP;
+		desc->link_sleep.link_sleep_cap = 0;
+		ret = desc->length;
+		break;
+	default:
+		maudc_err(udc, "%s: invalid Device Capability Type %i\n",
+			__func__, type);
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Finds an MA USB endpoint descriptor inside of an endpoint handle response.
+ */
+static void maudc_fill_ma_ep_desc(struct mausb_ep_des *ma_ep_des,
+		struct usb_endpoint_descriptor *ep_des,
+		struct mausb_host_ep *ma_ep)
+{
+	ma_ep_des->ep_handle.handle = ma_ep->ep_handle.handle;
+	ma_ep_des->dir = usb_endpoint_dir_in(ep_des) ? 1 : 0;
+	ma_ep_des->iso = usb_endpoint_xfer_isoc(ep_des) ? 1 : 0;
+	ma_ep_des->l_man = 0;
+	ma_ep_des->valid = 0;
+	ma_ep_des->rsvd_0 = 0;
+
+	if ((usb_endpoint_dir_out(ep_des) && !usb_endpoint_xfer_isoc(ep_des))
+			|| usb_endpoint_xfer_control(ep_des)) {
+		ma_ep_des->ccu = 1;
+	} else
+		ma_ep_des->ccu = 0;
+
+	ma_ep_des->rsvd_1 = 0;
+
+	if (usb_endpoint_dir_out(ep_des) || usb_endpoint_xfer_control(ep_des))
+		ma_ep_des->buffer_size = ma_ep->state.rx_buf_size;
+	else
+		ma_ep_des->buffer_size = 0;
+
+	if (usb_endpoint_xfer_isoc(ep_des)) {
+		/* TODO: iso transfers */
+		/* ma_ep_des->iso_prog_dly = 0; */
+		/* ma_ep_des->iso_resp_dly = 0; */
+	} else {
+		ma_ep_des->iso_prog_dly = 0;
+		ma_ep_des->iso_resp_dly = 0;
+	}
+}
+
+/**
+ * Handles incoming EPHandleReq packets and fills EPHandleResp fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_req(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleReq_flds *req,
+		struct mausb_EPHandleResp_flds *resp)
+{
+	int				i;
+	enum mausb_pkt_status		status = UNSUCCESSFUL;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct usb_endpoint_descriptor	*ep_des;
+	struct usb_ep			*usb_ep;
+	struct mausb_host_ep		*ma_ep;
+
+	resp->num_ep_des = req->num_ep_des;
+
+	/* TODO: Sanity check; make sure we dont look past end of packet */
+	for (i = 0; i < req->num_ep_des; ++i) {
+
+		ep_des = mausb_ep_handle_req_get_ep_des(req, i);
+
+		if (NULL != ep_des) {
+
+			ma_ep = mausb_find_ep_by_address(
+				ep_des->bEndpointAddress, mausb_dev);
+
+			if (NULL != ma_ep) {
+				maudc_warn(udc, "%s: endpoint already exists"
+					"  resetting . . .\n", __func__);
+				mausb_internal_drop_ep(ma_ep);
+			}
+
+			maudc_add_ma_ep(ep_des, mausb_dev, &ma_ep);
+
+			if (NULL == ma_ep) {
+				maudc_err(udc, "%s: failed to add endpoint"
+					" for entry %i\n", __func__, i);
+			}
+
+			maudc_fill_ma_ep_desc(&resp->ep_des[i], ep_des, ma_ep);
+
+			usb_ep = get_ep(udc, ep_des->bEndpointAddress);
+
+			if (NULL != usb_ep)
+				mausb_link_ma_ep_to_usb_ep(ma_ep, usb_ep);
+
+			/* Per spec, if at least 1 endpoint assignment
+			 * is sucessful, the packet returns success.
+			 */
+			status = SUCCESS;
+		}
+	}
+
+	return status;
+}
+
+/**
+ * Handles incoming EPHandleDeleteReq packets and fills EPHandleDeleteResp
+ * fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_del_req(
+		struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleDelete_flds *req,
+		struct mausb_EPHandleDelete_flds *resp)
+{
+	int				i;
+	int				ret = 0;
+	enum mausb_pkt_status		status = UNSUCCESSFUL;
+	struct mausb_udc		*udc = platform_get_drvdata(&udc_pdev);
+	struct mausb_host_ep		*ma_ep = NULL;
+	struct mausb_ep_handle		*req_handle;
+
+	resp->num_ep = 0;
+
+	/* TODO: Sanity check; make sure we dont look past end of packet */
+	for (i = 0; i < req->num_ep; ++i) {
+		req_handle = &req->ep_handle[i];
+
+		ma_ep = mausb_find_ep_by_handle(req_handle, mausb_dev);
+
+		ret = mausb_internal_drop_ep(ma_ep);
+
+		if (0 <= ret) {
+			/*
+			 * per spec, the packet returns sucess if it can
+			 * delete at least 1 endpoint
+			 */
+			status = SUCCESS;
+
+		} else {
+			resp->ep_handle[resp->num_ep].handle
+						= req_handle->handle;
+			resp->num_ep++;
+
+			maudc_err(udc, "%s: could not delete endpoint with"
+				" handle %x\n", __func__, req_handle->handle);
+		}
+	}
+
+	return status;
+}
+
+/**
+ * Inactivate endpoints in EPInactivateReq packet and fill
+ * EPInactivateResp fields.
+ */
+static enum mausb_pkt_status maudc_handle_ep_inactivate(
+		struct mausb_EPInactivateReq_flds *req,
+		struct mausb_EPInactivateResp_flds *resp,
+		struct mausb_dev *dev)
+{
+	int			i = 0;
+	int			failures = 0;
+	enum			mausb_pkt_status status = SUCCESS;
+	struct mausb_host_ep	*ma_ep = NULL;
+	struct mausb_ep_handle	*req_handle;
+
+	for (i = 0; i < req->num_ep_handles; ++i) {
+		req_handle = &req->ep_handle[i];
+		ma_ep = mausb_find_ep_by_handle(req_handle, dev);
+
+		if (!ma_ep) {
+			resp->ep_handle[failures] = *req_handle;
+			status = UNSUCCESSFUL;
+			failures++;
+		} else
+			ma_ep->ep_handle_state = MAUSB_EP_HANDLE_INACTIVE;
+	}
+
+	resp->num_ep_with_error = failures;
+
+	return status;
+}
+
+/**
+ * This function handles management requests to the UDC. It parses the packet
+ * and makes the necessary function calls into the system.
+ *
+ * @req:	The incoming request to handle.
+ * @resp: 	The response packet to send out.
+ * @mgmt:	The MA USB management structure associated with transfer.
+ *
+ * Note: this function only fills the packet type, status and
+ * request-specific data-fields. The remainder of the fields are set by
+ * mausb_rx_mgmt_req.
+ */
+static int udc_mgmt_req_switch(struct mausb_mgmt_pkt *req,
+		struct mausb_mgmt_pkt *resp, struct mausb_mgmt *mgmt)
+{
+	int			ret = -EINVAL;
+	int			desc_count = 0;
+	int			offset = 0;
+	struct ma_dev		*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_udc	*udc = mausb_ma_dev_to_udc(ma_dev);
+
+	/* always set the device handle */
+	req->common.dev_handle = udc->mausb_dev->dev_handle;
+
+	switch (req->common.pkt_type) {
+
+	case CapReq:
+		/* non-hub devices require a Speed Capability Descriptor */
+		ret = add_cap_desc(resp, MAUSB_DEV_CAP_SPEED, offset);
+		if (ret <= 0) {
+			maudc_err(udc, "%s: could not add speed capability "
+				"descriptor\n", __func__);
+		} else {
+			desc_count++;
+			offset += ret;
+		}
+
+		ret = add_cap_desc(resp, MAUSB_DEV_CAP_LINK_SLEEP, offset);
+		if (ret <= 0) {
+			maudc_err(udc, "%s; could not add link sleep"
+				 " capability descriptor\n", __func__);
+		} else {
+			desc_count++;
+			offset += ret;
+		}
+
+		/*
+		 * TODO: if want to add more device cap descriptors, this would
+		 * be a good place to do it.
+		 */
+
+		resp->common.pkt_type = CapResp;
+		resp->common.pkt_status = NO_ERROR;
+		resp->cap_resp.num_ep = CAP_MAX_EP_NUM;
+		resp->cap_resp.num_dev = CAP_MAX_DEV_NUM;
+		resp->cap_resp.num_stream = EP_MAX_STREAMS;
+		resp->cap_resp.dev_type = CAP_DEV_TYPE;
+		resp->cap_resp.desc_count = desc_count;
+		resp->cap_resp.desc_length = offset;
+		resp->cap_resp.max_tx_reqs = CAP_MAX_TX_REQS;
+		resp->cap_resp.max_mgmt_reqs = CAP_MAX_MGMT_REQS;
+
+		ret = 0;
+		break;
+	case USBDevHandleReq:
+		udc->mausb_dev->dev_handle = MAUDC_DEV_HANDLE;
+
+		resp->common.pkt_type     = USBDevHandleResp;
+		resp->common.pkt_status   = NO_ERROR;
+		resp->usb_dev_handle_resp = MAUDC_DEV_HANDLE;
+
+		ret = 0;
+		break;
+	case EPHandleReq:
+		resp->common.pkt_type   = EPHandleResp;
+		resp->usb_dev_handle_resp = udc->mausb_dev->dev_handle;
+		resp->common.pkt_status = maudc_handle_ep_req(udc->mausb_dev,
+			&req->ep_handle_req, &resp->ep_handle_resp);
+		ret = 0;
+		break;
+	case EPActivateReq:
+		break;
+	case EPInactivateReq:
+		resp->common.pkt_type   = EPInactivateResp;
+		resp->common.pkt_status = maudc_handle_ep_inactivate(
+						&req->ep_inactivate_req,
+						&resp->ep_inactivate_resp,
+						udc->mausb_dev);
+		ret = 0;
+		break;
+	case EPResetReq:
+		break;
+	case EPClearTransferReq:
+		break;
+	case EPHandleDeleteReq:
+		resp->common.pkt_type   = EPHandleDeleteResp;
+
+		resp->common.pkt_status = maudc_handle_ep_del_req(
+			udc->mausb_dev, &req->ep_handle_delete,
+					&resp->ep_handle_delete);
+		ret = 0;
+		break;
+	case DevResetReq:
+		resp->common.pkt_type   = DevResetResp;
+
+		ma_dev->ma_dev_addr = req->common.ma_dev_addr;
+		ma_dev->mass_id = req->common.mass_id;
+
+		ret = 0;
+
+		if (0 == ret) {
+			resp->common.pkt_status = NO_ERROR;
+		} else {
+			resp->common.pkt_status =
+				mausb_errno_to_ma_status(ret);
+		}
+		break;
+	case ModifyEP0Req:
+		resp->common.pkt_type   = ModifyEP0Resp;
+		resp->common.pkt_status = SUCCESS;
+
+		/*
+		 * TODO: fix so to spec - for now we don't track USB device
+		 * state and can't do proper checks.
+		 */
+		if (req->modify_ep0_req.ep_handle.dev_addr == 0) {
+			/* && USB device is in addressed state) { */
+			resp->modify_ep0_resp.ep_handle.handle =
+				req->modify_ep0_req.ep_handle.handle
+					| (MAUDC_DEV_ADDR << 5);
+		} else {
+			resp->modify_ep0_resp.ep_handle.handle = 0;
+		}
+
+		ret = 0;
+		break;
+	case SetUSBDevAddrReq:
+		resp->common.pkt_type   = SetUSBDevAddrResp;
+		resp->common.pkt_status = NO_ERROR;
+		udc->mausb_dev->dev_address = MAUDC_DEV_ADDR;
+
+		resp->set_dev_addr_resp.dev_addr = udc->mausb_dev->dev_address;
+		ret = 0;
+		break;
+	case UpdateDevReq:
+		break;
+	case USBDevDisconnectReq:
+		resp->common.pkt_type   = USBDevDisconnectResp;
+		resp->common.dev_handle	= req->common.dev_handle;
+		resp->common.pkt_status = NO_ERROR;
+		ret = 0;
+		break;
+	case DevDisconnectReq:
+		resp->common.pkt_type   = DevDisconnectResp;
+		resp->common.dev_handle	= 0;
+		resp->common.pkt_status = NO_ERROR;
+		ret = 0;
+		break;
+	case SleepReq:
+		resp->common.pkt_type   = SleepResp;
+		resp->common.pkt_status = NO_ERROR;
+		mausb_device_suspend();
+		ret = 0;
+		break;
+	case WakeReq:
+		resp->common.pkt_type   = WakeResp;
+		resp->common.pkt_status = NO_ERROR;
+		mausb_device_resume();
+		ret = 0;
+		break;
+	case PingReq:
+		break;
+	case SyncReq:
+		break;
+	case CancelTransferReq:
+		resp->common.pkt_type   = CancelTransferResp;
+		resp->common.pkt_status = NO_ERROR;
+		resp->cancel_transfer_resp.ep_handle =
+				req->cancel_transfer_req.ep_handle;
+		resp->cancel_transfer_resp.stream_id =
+				req->cancel_transfer_req.stream_id;
+		resp->cancel_transfer_resp.req_id =
+				req->cancel_transfer_req.req_id;
+		/* TODO: cancel transfer and set fields below accordingly */
+		resp->cancel_transfer_resp.cancel_status = 1;
+		resp->cancel_transfer_resp.deliv_seq_num = 0;
+		resp->cancel_transfer_resp.deliv_byte_offset = 0;
+		ret = 0;
+		break;
+	case EPOpenStreamReq:
+		break;
+	case EPCloseStreamReq:
+		break;
+	case USBDevResetReq:
+		break;
+	case VendorSpecificReq:
+		break;
+
+	/* Invalid packet type */
+	default:
+		maudc_err(udc, "%s: invalid packet type\n", __func__);
+		ret = -EBADMSG;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * MA USB ep0 endpoint descriptor for a super speed endpoint
+ * per spec section 7.3.2.2.
+ */
+static struct usb_endpoint_descriptor mausb_ep0_desc = {
+
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0x00,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = 512,
+	.bInterval = 0
+};
+
+/**
+ * UDC probe function
+ */
+int mausb_udc_probe(struct platform_device *pdev)
+{
+	int				ret = 0;
+	int				i;
+	struct mausb_udc		*udc;
+	struct usb_ep			*usb_ep;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		return -ENOMEM;
+
+	udc->udc_lock = __SPIN_LOCK_UNLOCKED(udc->udc_lock);
+	/* initialize gadget structure */
+	udc->gadget.name = UDC_NAME;
+	udc->gadget.ops = &mudc_ops;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed = USB_SPEED_SUPER;
+	udc->gadget.dev.parent = &pdev->dev;
+
+	/* set head for list of gadget endpoints   */
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	/* initalize the ma_dev structure */
+	mausb_init_ma_device(&udc->ma_dev, 0, 0,
+		NULL, udc, &udc_mgmt_req_switch, &check_for_device);
+
+	udc->mausb_dev = mausb_internal_alloc_dev(&udc->ma_dev, NULL,
+		&udc->gadget);
+
+	for (i = 0; i < MAUDC_MAX_NUM_EP; i++) {
+		usb_ep = &udc->usb_ep[i].dev_ep;
+
+		usb_ep->name = ep_name[i];
+		usb_ep->ops = &mausb_ep_ops;
+		usb_ep->maxpacket = EP_MAX_PACKET;
+		usb_ep->max_streams = EP_MAX_STREAMS;
+
+		list_add_tail(&usb_ep->ep_list, &udc->gadget.ep_list);
+
+		INIT_LIST_HEAD(&udc->usb_ep[i].usb_req_list);
+	}
+
+	/* give gadget driver ep0 then remove from list*/
+	udc->usb_ep[0].dev_ep.desc = &mausb_ep0_desc;
+	udc->gadget.ep0 = &udc->usb_ep[0].dev_ep;
+	list_del_init(&udc->usb_ep[0].dev_ep.ep_list);
+
+	/* add a new gadget to the udc class driver list */
+	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "%s: could not add gadget UDC, error %d\n",
+			__func__, ret);
+	} else
+		platform_set_drvdata(pdev, udc);
+
+	return ret;
+}
+
+int mausb_udc_remove(struct platform_device *pdev)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: removing udc\n", __func__);
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	return 0;
+}
+
+int mausb_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: suspending udc\n", __func__);
+
+	udc->suspended = 1;
+
+	return 0;
+}
+
+int mausb_udc_resume(struct platform_device *pdev)
+{
+	struct mausb_udc *udc = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "%s: resuming udc\n", __func__);
+
+	udc->suspended = 0;
+
+	return 0;
+}
+
+/**
+ * platform structures for USB Device Controller (UDC)
+ */
+static struct platform_device udc_pdev = {
+	.name = UDC_NAME,
+	.id = 0
+};
+
+static struct platform_driver udc_driver = {
+	.probe = mausb_udc_probe,
+	.remove = mausb_udc_remove,
+	.suspend = mausb_udc_suspend,
+	.resume = mausb_udc_resume,
+	.driver = {
+		.name = UDC_NAME,
+		.owner = THIS_MODULE
+	}
+};
+
+/**
+ * initialization function
+ *
+ * TODO: get rid of platform device and replace with "virtual" device
+ */
+static int mausb_udc_init(void)
+{
+	int ret;
+
+	pr_debug("loading MA USB UDC . . .\n");
+
+	/* register UDC driver */
+	ret = platform_driver_register(&udc_driver);
+	if (ret < 0) {
+		pr_err("failed to register UDC driver: err %d\n", ret);
+	} else {
+		/* register UDC device */
+		ret = platform_device_register(&udc_pdev);
+		if (ret < 0) {
+			pr_err("failed to register UDC device: err %d\n", ret);
+			platform_driver_unregister(&udc_driver);
+
+		} else {
+			/* direct the release function (for exiting) */
+			udc_pdev.dev.release = &udc_dev_release;
+		}
+	}
+
+	return ret;
+}
+module_init(mausb_udc_init);
+
+/**
+ * exit function
+ */
+static void mausb_udc_exit(void)
+{
+	/* deregister UDC device */
+	platform_device_unregister(&udc_pdev);
+
+	/* deregister UDC driver */
+	platform_driver_unregister(&udc_driver);
+
+}
+module_exit(mausb_udc_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("mausb_udc");
diff --git a/drivers/staging/mausb/drivers/mausb_udc.h b/drivers/staging/mausb/drivers/mausb_udc.h
new file mode 100644
index 0000000..b900b2d
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_udc.h
@@ -0,0 +1,147 @@
+/* name:	mausb_udc.h
+ * description:	header file for mausb_udc.h
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.o.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_UDC_H
+#define __MAUSB_UDC_H
+
+#include <linux/timer.h>
+#include <linux/usb/gadget.h>
+#include "mausb_state.h"
+#include "mausb_pkt.h"
+#include "mausb_msapi.h"
+#include "mausb_mem.h" /* for mgmt structure */
+#include "mausb_const.h"
+
+#define UDC_NAME "mausb udc"
+#define MAUDC_MAX_NUM_EP 3
+#define EP_MAX_PACKET  64  /* max number of packets ep can handle */
+#define EP_MAX_STREAMS 16 /* max number of streams ep can handle */
+#define REQ_BUF_SIZE   64
+#define CAP_MAX_EP_NUM	3 /* max number of endpoints state can be tracked for */
+#define CAP_MAX_DEV_NUM 1 /* max number of devices that can be managed
+			   * note this is 1 because only hubs can have >1 */
+#define CAP_DEV_TYPE	0 /* device type: 0 = not an MA USB hub
+			   *		  1 = USB 2.0 hub
+			   *		  2 = USB 3.1 hub */
+#define CAP_MAX_TX_REQS 0x01FF /* max number of outstanding transfer requests
+				* device can track - arbitrarily chosen */
+#define CAP_MAX_MGMT_REQS 0x01F /* max number of outstanding management requests
+				 * device can track - arbitrarily chosen */
+
+#define MAUDC_DEV_HANDLE 0x1359 /* MA Device handle for the USB device */
+
+#define MAUDC_DEV_ADDR 0x7D /* USB Device address for the USB device */
+			/* Note: MAUDC_DEV_ADDR is arbitrary */
+
+#define MAUDC_BUS_NUM 0xD /* Bus number to be used in the endpoint handle */
+
+#define MAUSB_GADGET_TIMEOUT 3	/* time out for gadget driver enqueue request */
+
+#define maudc_info(udc, fmt, args...) \
+	dev_info(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_dbg(udc, fmt, args...) \
+	dev_dbg(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_warn(udc, fmt, args...) \
+	dev_warn(udc->gadget.dev.parent , fmt , ## args)
+#define maudc_err(udc, fmt, args...) \
+	dev_err(udc->gadget.dev.parent , fmt , ## args)
+
+/* function declarations */
+void udc_dev_release(struct device *dev);
+int mausb_udc_probe(struct platform_device *pdev);
+int mausb_udc_remove(struct platform_device *pdev);
+int mausb_udc_suspend(struct platform_device *pdev, pm_message_t state);
+int mausb_udc_resume(struct platform_device *pdev);
+int check_for_device(int dont_use);
+
+
+/* function declarations */
+int do_ma_transfer(struct mausb_host_ep *ep, struct mausb_pkt *tx_req,
+		bool dir_in);
+/**
+ * UDC structure
+ *
+ * The UDC structure holds all of the per-device data. This includes both the
+ * media agnostic device data as well as the USB device data. The USB device
+ * connected to the UDC is considered an integrated USB Device.
+ *
+ * @mausb_gadget_ep:	An array of all the endpoints for this device.
+ * @usb_gadget:		The device's gadget structure.
+ * @usb_gadget_driver:	the device's driver.
+ * @ma_dev:		The media agnostic device structure. Holds all the
+ *			data common to all media agnostic devices.
+ * @mausb_dev:		Holds media agnostic data that represents a USB device.
+ * @ms_driver:		The MAUSB driver's interface with the media specific
+ *			driver.
+ * @udc_lock:		The 'big' lock. Used to protect this structure's data
+ *            		from concurrent access.
+ * @dev_status:		Holds USB device status.
+ * @suspended:		1 when UDC is suspended, otherwise 0.
+ * @pullup:		1 when a USB device is connecting to UDC, otherwise 0.
+ */
+struct mausb_udc {
+	struct mausb_gadget_ep		usb_ep[MAUDC_MAX_NUM_EP];
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	struct ma_dev			ma_dev;
+	struct mausb_dev		*mausb_dev;
+	spinlock_t			udc_lock;
+	u16				dev_status;
+	unsigned			suspended:1;
+	unsigned			pullup:1;
+};
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 07/10] added media agnostic (MA) USB management packet handling
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (4 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

The Media Agnostic USB Specification outlines a number of managment
packet types for management and control functions. Each function is
initiated with a particular type of managment request packet and
completed with the corresponding management response packet. This
is where we fill the fields for outgoing management packets and parse
and handle incoming management packets.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_mgmt.c | 888 +++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_mgmt.h |  88 +++
 2 files changed, 976 insertions(+)
 create mode 100755 drivers/staging/mausb/drivers/mausb_mgmt.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_mgmt.h

diff --git a/drivers/staging/mausb/drivers/mausb_mgmt.c b/drivers/staging/mausb/drivers/mausb_mgmt.c
new file mode 100755
index 0000000..7301ae3
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mgmt.c
@@ -0,0 +1,888 @@
+/* name:	mausb_mgmt.c
+ * description: Handles management packet operations common to both
+ *              hosts and devices. This includes parsing incoming packets,
+ *              as well as creating outgoing packets.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+
+#include "mausb_pkt.h"
+#include "mausb_mgmt.h"
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+#include "mausb_const.h"
+
+/**
+ * Returns the ma_dev structure for a given device.
+ */
+struct ma_dev *mausb_mgmt_to_ma_dev(struct mausb_mgmt *mgmt)
+{
+	return container_of(mgmt, struct ma_dev, mgmt);
+}
+EXPORT_SYMBOL(mausb_mgmt_to_ma_dev);
+
+/**
+ * Opens a connection to the Media Specific driver to pass management packets
+ * to a particular MA device.
+ *
+ * The caller should be holding the lock protecting the MA device's data.
+ *
+ * Returns 0 on success, or a negative errno on failure.
+ *
+ * @mgmt:		The struct for the management channel to the MA device.
+ *              	after this function
+ * @drv:		The specific medium we are communicating with
+ * @transfer_pkt:	A pointer to the function that should be called by the
+ *                    	MS driver to pass incoming management packets to the
+ *                    	MA driver.
+ * @pkt_sent:		Completion callback for outgoing management packets.
+ *			This function will be called by the MS driver once a
+ *			packet has been sent to the medium to indicate that
+ *			it is done with the packet. Note: the completion
+ *			callback can be disabled by setting this to NULL.
+ */
+int mausb_add_mgmt_channel(struct mausb_mgmt *mgmt, struct mausb_ms_drv *drv,
+		int  (*transfer_pkt)(struct ms_pkt *pkt, void *context),
+		void (*pkt_sent)(struct ms_pkt *pkt))
+{
+	int				ret = 0;
+	struct mausb_transfer_pair	tx_pair;
+	unsigned long			irq_flags;
+
+	tx_pair.to_ma.transfer_packet = transfer_pkt;
+	tx_pair.pkt_sent = pkt_sent;
+	tx_pair.to_ma.context = mgmt;
+	tx_pair.handle = MAUSB_MGMT_HANDLE;
+
+	ret = drv->ops->add_transfer_pair(&tx_pair);
+
+	if (ret >= 0) {
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+		mgmt->tx_pair = tx_pair;
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_add_mgmt_channel);
+
+/**
+ * Fills the fields in an endpoint handle req.
+ *
+ * @dev:	The device struct that contains the endpoints to open.
+ * @req_flds:	The req_flds to fill.
+ *
+ * Note: this function can only be used on the host side.
+ */
+int mausb_fill_ep_handle_req_flds(struct mausb_dev *mausb_dev,
+		struct mausb_mgmt_pkt *req, bool add)
+{
+	int				   i = 0;
+	struct mausb_host_ep		   *ma_ep;
+	unsigned long			   irq_flags;
+	struct mausb_ss_ep_req		   *ss_ep_des;
+	struct mausb_ep_req		   *ep_des;
+	struct mausb_EPHandleReq_flds	   *req_flds = &req->ep_handle_req;
+	struct mausb_EPHandleDelete_flds   *del_flds = &req->ep_handle_delete;
+
+	req_flds->num_ep_des = 0;
+
+	if (USB_SPEED_SUPER == mausb_dev->dev->speed)
+		req_flds->size_ep_des = cpu_to_le32(MAUSB_SS_EP_REQ_SIZE);
+	else
+		req_flds->size_ep_des = cpu_to_le32(MAUSB_EP_REQ_SIZE);
+
+	/* for every endpoint */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+		/* if we need to add this endpoint */
+		if (add && (MAUSB_EP_HANDLE_UNASSIGNED
+					== ma_ep->ep_handle_state)) {
+
+			if (USB_SPEED_SUPER == mausb_dev->dev->speed &&
+				ma_ep->ep->desc.bEndpointAddress != 0x00) {
+				ss_ep_des = &req_flds->ss_ep_des[i];
+
+				memcpy(&ss_ep_des->ep_des,
+					&ma_ep->ep->desc,
+					USB_DT_ENDPOINT_SIZE);
+
+				memcpy(&ss_ep_des->ss_ep_comp_des,
+					&ma_ep->ep->ss_ep_comp,
+					USB_DT_SS_EP_COMP_SIZE);
+			} else {
+				ep_des = &req_flds->ep_des[i];
+
+				memcpy(&ep_des->ep_des,
+					&ma_ep->ep->desc,
+					USB_DT_ENDPOINT_SIZE);
+			}
+
+			if (ma_ep->ep->desc.bEndpointAddress == 0x00)
+				req_flds->size_ep_des = MAUSB_EP_REQ_SIZE;
+
+			i++;
+			req_flds->num_ep_des = i;
+
+		/* if we need to delete this endpoint */
+		} else if (!add &&
+			(MAUSB_EP_HANDLE_DELETED == ma_ep->ep_handle_state)) {
+
+			del_flds->ep_handle[i].handle =
+				cpu_to_le16(ma_ep->ep_handle.handle);
+
+			i++;
+			req_flds->num_ep_des = i;
+		}
+
+		spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	if (i <= 0)
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
+ * Looks for inactive endpoints and fills EPInactivateReq packet fields
+ * accordingly.
+ */
+int mausb_fill_ep_inactivate_req_flds(struct mausb_dev *mausb_dev,
+		struct mausb_mgmt_pkt *req)
+{
+	int				    i = 0;
+	struct mausb_host_ep		    *ma_ep;
+	unsigned long			    irq_flags;
+	struct mausb_EPInactivateReq_flds   *req_flds = &req->ep_inactivate_req;
+
+	/*
+	 * Grab any inactive endpoints. After EPInactivateReq is sent, inactive
+	 * endoints will be marked for deletion.
+	 */
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
+		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+		spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+		/* If endpoint has been inactivated, include it in packet. */
+		if (ma_ep->ep_handle_state == MAUSB_EP_HANDLE_INACTIVE) {
+			req_flds->ep_handle[i] = ma_ep->ep_handle;
+			i++;
+			req_flds->num_ep_handles = i;
+			ma_ep->ep_handle_state = MAUSB_EP_HANDLE_DELETED;
+		}
+
+		spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	}
+
+	/*TODO: set suspend flag when needed */
+
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+	return req_flds->num_ep_handles;
+}
+
+/**
+ * Transmits a mausb management packet req and awaits a resp
+ *
+ * Caller should be holding the lock in the mausb_mgmt structure.
+ *
+ * This function transmits a MA USB management request packet and waits for a
+ * response. If a response packet is received, this function will return
+ * 0 with valid data in the resp. If the request timed out, will return
+ * -ETIMEDOUT.
+ *
+ * Note: since the calling process sleeps, this function CANNOT be called
+ *       from an interrupt context.
+ *
+ * @req:	A pointer to the MA USB transferRequest packet to be sent.
+ * @resp:	A pointer to the MA USB transferResponse packet received.
+ * @ma_mgmt:	The Ma USB device's management structure.
+ */
+static int internal_mausb_tx_mgmt_req(struct mausb_pkt *req,
+		struct mausb_pkt **resp, struct mausb_mgmt *ma_mgmt)
+{
+	int				retries = 0;
+	int				rem_time = 0;
+	struct mausb_mgmt_req_list	*req_entry;
+	struct mausb_pkt_transfer	*transfer;
+	unsigned long			irq_flags = 0;
+
+	if (NULL == ma_mgmt->tx_pair.to_ms.transfer_packet)
+		return -EPIPE;
+	else
+		transfer = &ma_mgmt->tx_pair.to_ms;
+
+	req_entry = kzalloc(sizeof(struct mausb_mgmt_req_list), GFP_ATOMIC);
+	if (!req_entry)
+		return -ENOMEM;
+
+	req_entry->mgmt_req = req;
+	req_entry->mgmt_resp = NULL;
+	init_completion(&req_entry->resp_rcvd);
+	INIT_LIST_HEAD(&req_entry->req_list);
+
+	list_add_tail(&req_entry->req_list, &ma_mgmt->req_list);
+
+	req->common->length = cpu_to_le16(mausb_pkt_length(req));
+
+	ma_mgmt->token = (ma_mgmt->token % MAUSB_MGMT_MAX_TOKEN) + 1;
+	req->mgmt->token = ma_mgmt->token;
+
+	/* until we time out or complete */
+	for (retries = 0; (retries <= MAUSB_MGMT_TRANSFER_RETRIES) &&
+			(NULL == req_entry->mgmt_resp); retries++) {
+
+		/* if this is a retry */
+		if (retries > 0)
+			req->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+
+		spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+
+		mausb_pkt_fill_ms_pkt(req, GFP_ATOMIC);
+
+		mamgmt_dbg("%s: sending %s packet\n", __func__,
+			mausb_type_to_string(req->common->pkt_type));
+		transfer->transfer_packet(&req->pkt, transfer->context);
+
+		rem_time = wait_for_completion_interruptible_timeout(
+			&req_entry->resp_rcvd, MAUSB_MGMT_RT_DELAY);
+
+		spin_lock_irqsave(ma_mgmt->ma_dev_lock, irq_flags);
+	}
+
+	list_del(&req_entry->req_list);
+	*resp = req_entry->mgmt_resp;
+
+	kfree(req_entry);
+
+	if (rem_time == 0) /* if we timed out */
+		return -ETIMEDOUT;
+	else if (rem_time < 0) /* if an error happened */
+		return rem_time;
+	else /* return based on the status of the response */
+		return 0;
+}
+
+/**
+ * Accepts the EPHandleResp and EPHandleReq Fields and updates
+ * endpoint(s) state based on the Resp Fields.
+ */
+static int mausb_handle_ep_resp(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleReq_flds *req,
+		struct mausb_EPHandleResp_flds *resp)
+{
+	int				i;
+	int				ret = -EINVAL;
+	struct mausb_host_ep		*ma_ep;
+	struct usb_endpoint_descriptor	*ep_des;
+
+	if (le32_to_cpu(req->num_ep_des) != le32_to_cpu(resp->num_ep_des))
+		return -EINVAL;
+
+	for (i = 0; i < resp->num_ep_des; ++i) {
+
+		ep_des = mausb_ep_handle_req_get_ep_des(req, i);
+		if (NULL != ep_des) {
+
+			ma_ep = mausb_find_ep_by_desc(ep_des, mausb_dev);
+			if (ma_ep != NULL)
+				ret = mausb_update_ep(ma_ep, &resp->ep_des[i]);
+			else {
+				mamgmt_err("%s: could not find endpoint"
+				" for handle #%i (%x)\n", __func__, i,
+				le16_to_cpu(resp->ep_des[i].ep_handle.handle));
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Accepts the EPHandleDeleteReq and EPHandleDeleteResp Fields and updates
+ * the endpoint(s) state based on the Resp Fields.
+ */
+static int mausb_handle_ep_del_resp(struct mausb_dev *mausb_dev,
+		struct mausb_EPHandleDelete_flds *req,
+		struct mausb_EPHandleDelete_flds *resp)
+{
+	int ret			      = 0;
+	int			      i, j;
+	bool			      drop_failed;
+	struct mausb_host_ep	      *ma_ep;
+	struct mausb_ep_handle	      *req_handle;
+	struct mausb_ms_drv	      *ms_driver = mausb_dev->ma_dev->ms_driver;
+
+	/* for every endpoint in the req */
+	for (i = 0; i < req->num_ep; ++i) {
+
+		drop_failed = false;
+		req_handle = &req->ep_handle[i];
+
+		for (j = 0; j < le32_to_cpu(resp->num_ep); ++j) {
+			if (req_handle->handle ==
+				le16_to_cpu(resp->ep_handle[j].handle))
+
+				drop_failed = true;
+		}
+
+		if (false == drop_failed) {
+
+			ma_ep = mausb_find_ep_by_handle(req_handle, mausb_dev);
+
+			ret = ms_driver->ops->drop_transfer_pair(
+				ma_ep->ep_handle.handle,
+				ma_ep->tx_pair.to_ms.context);
+
+			if (0 <= ret) {
+				/* drop the endpoint locally */
+				ret = mausb_internal_drop_ep(ma_ep);
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Determines the speed to report in the USBDevHandleReq.
+ */
+static __u8 mausb_get_dev_speed(struct mausb_dev *dev)
+{
+	switch (dev->dev->speed) {
+	case USB_SPEED_LOW:
+		return MAUSB_LOW_SPEED;
+	case USB_SPEED_FULL:
+		return MAUSB_FULL_SPEED;
+	case USB_SPEED_HIGH:
+		return MAUSB_HIGH_SPEED;
+	case USB_SPEED_SUPER:
+		return MAUSB_SUPER_SPEED;
+	/* TODO: SUPER_SPEED_PLUS */
+	default:
+		return MAUSB_INVALID_SPEED;
+	}
+}
+
+/**
+ * Parses all descriptors for a given CapResp packet and stores data in
+ * corresponding device data structure.
+ *
+ * Returns number of descriptors read.
+ */
+int parse_cap_desc(struct mausb_pkt *resp, struct ma_dev *ma_dev)
+{
+	int			   ret = 0;
+	int			   offset = 0;
+	int			   desc_count = resp->mgmt->cap_resp.desc_count;
+	struct mausb_dev_cap_desc  *desc;
+
+	offset = MAUSB_PKT_HEADER_SIZE + sizeof(struct mausb_CapResp_flds);
+	desc = cap_desc_ptr_increment(resp->mgmt, offset);
+
+	if (resp->common->pkt_type != CapResp) {
+		mamgmt_err("%s: packet is type %i (not a CapResp)\n", __func__,
+			resp->common->pkt_type);
+		return -EINVAL;
+	}
+
+	while (desc_count) {
+		if (desc == NULL) {
+			mamgmt_err("%s: no descriptor to read\n", __func__);
+			return ret;
+		}
+
+		ret++;
+
+		switch (desc->cap_type) {
+		case MAUSB_DEV_CAP_SPEED:
+			ma_dev->speed = kzalloc(
+				sizeof(struct mausb_dev_cap_speed),
+				GFP_ATOMIC);
+			ma_dev->speed->speed = desc->speed.speed;
+			ma_dev->speed->lse = desc->speed.lse;
+			ma_dev->speed->st = desc->speed.st;
+			ma_dev->speed->lane_count =
+				desc->speed.lane_count;
+			ma_dev->speed->link_protocol =
+				desc->speed.link_protocol;
+			ma_dev->speed->lsm = desc->speed.lsm;
+			break;
+		case MAUSB_DEV_CAP_POUT:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_pout),
+				GFP_ATOMIC);
+			ma_dev->pout->elastic_buf_cap =
+				desc->pout.elastic_buf_cap;
+			ma_dev->pout->drop_notif =
+				desc->pout.drop_notif;
+			break;
+		case MAUSB_DEV_CAP_ISO:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_iso),
+				GFP_ATOMIC);
+			ma_dev->iso->iso_alignment =
+				desc->iso.iso_alignment;
+			break;
+		case MAUSB_DEV_CAP_SYNC:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_sync),
+				GFP_ATOMIC);
+			ma_dev->sync->media_time_avail =
+				desc->sync.media_time_avail;
+			ma_dev->sync->timestamp_req =
+				desc->sync.timestamp_req;
+			break;
+		case MAUSB_DEV_CAP_CONT_ID:
+			ma_dev->pout = kzalloc(
+				sizeof(struct mausb_dev_cap_cont_id),
+				GFP_ATOMIC);
+			ma_dev->cont_id->cont_id_upper =
+				desc->cont_id.cont_id_upper;
+			ma_dev->cont_id->cont_id_lower =
+				desc->cont_id.cont_id_lower;
+			break;
+		case MAUSB_DEV_CAP_LINK_SLEEP:
+			ma_dev->link_sleep = kzalloc(
+				sizeof(struct mausb_dev_cap_link_sleep),
+				GFP_ATOMIC);
+			ma_dev->link_sleep->link_sleep_cap =
+				desc->link_sleep.link_sleep_cap;
+			break;
+		default:
+			mamgmt_err("%s: unknown device capability descriptor"
+				" type %i\n", __func__, desc->cap_type);
+			ret--;
+			break;
+		}
+
+		desc_count--;
+		offset += desc->length;
+		desc = cap_desc_ptr_increment(resp->mgmt, offset);
+	}
+
+	return ret;
+}
+
+/**
+ * Transmits a management packet of the specified type for the given device.
+ *
+ * @type:	The type of MA USB management request packet being sent.
+ * @mgmt:	The management data we need to send the packet.
+ * @dev:	The device this packet is associated with. Set to NULL if
+ *	        there is no associated device (ex: for MAUSBDevReset).
+ * @host:	Set TRUE to indicate we are a host, set to FALSE if we are
+ *              a device.
+ */
+int mausb_tx_dev_mgmt_req(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host)
+{
+	return mausb_tx_dev_mgmt_req_ep(type, mgmt, dev, host, NULL);
+}
+EXPORT_SYMBOL(mausb_tx_dev_mgmt_req);
+
+/**
+ * Only necessary to call directly if you need to specify an EP, otherwise
+ * mausb_tx_dev_mgmt_req will work.
+ */
+int mausb_tx_dev_mgmt_req_ep(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host, struct mausb_host_ep *ma_ep)
+{
+	int			ret = 0;
+	struct mausb_pkt	*req;
+	struct mausb_pkt	*resp = NULL;
+	struct ma_dev		*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_dev	*hub;
+	unsigned long		irq_flags;
+
+	req = mausb_alloc_pkt(MAUSB_PKT_TYPE_MGMT, &ret, GFP_ATOMIC);
+	if (!req)
+		return -ENOMEM;
+
+	spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	req->common->ver_flags  |= MAUSB_VERSION_1_0;
+	req->common->pkt_type    = type;
+	if (NULL != dev)
+		req->common->dev_handle  = cpu_to_le16(dev->dev_handle);
+
+	req->common->ma_dev_addr = ma_dev->ma_dev_addr;
+	req->common->mass_id     = ma_dev->mass_id;
+	req->common->pkt_status  = NO_ERROR;
+
+	if (host)
+		req->common->ver_flags  |= MAUSB_PKT_FLAG_HOST;
+
+	switch (type) {
+	case CapReq:
+		req->mgmt->cap_req.max_mgmt_reqs = MAUSB_MGMT_MAX_TOKEN;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (0 <= ret) {
+			ma_dev->ma_cap.num_ep = resp->mgmt->cap_resp.num_ep;
+			ma_dev->ma_cap.num_dev = resp->mgmt->cap_resp.num_dev;
+			ma_dev->ma_cap.num_stream =
+					resp->mgmt->cap_resp.num_stream;
+			ma_dev->ma_cap.dev_type = resp->mgmt->cap_resp.dev_type;
+			ma_dev->ma_cap.max_tx_reqs =
+					resp->mgmt->cap_resp.max_tx_reqs;
+			ma_dev->ma_cap.max_mgmt_reqs =
+					resp->mgmt->cap_resp.max_mgmt_reqs;
+
+			/* look for descriptors */
+			if (resp->mgmt->cap_resp.desc_count > 0) {
+				ret = parse_cap_desc(resp, ma_dev);
+
+				if (ret != resp->mgmt->cap_resp.desc_count) {
+					mamgmt_err("%s: error reading"
+						" capability descriptors\n",
+						__func__);
+				}
+			}
+		}
+		break;
+
+	case EPHandleReq:
+		mausb_fill_ep_handle_req_flds(dev, req->mgmt, MAUSB_ADD);
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		if (0 <= ret) {
+			ret = mausb_handle_ep_resp(dev,
+				&req->mgmt->ep_handle_req,
+				&resp->mgmt->ep_handle_resp);
+		}
+		break;
+	case EPActivateReq:
+	case EPInactivateReq:
+		ret = mausb_fill_ep_inactivate_req_flds(dev, req->mgmt);
+		if (ret > 0)
+			ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case EPResetReq:
+	case EPClearTransferReq:
+		break;
+	case EPHandleDeleteReq:
+		mausb_fill_ep_handle_req_flds(dev, req->mgmt, MAUSB_DEL);
+
+		if (0 < le32_to_cpu(req->mgmt->ep_handle_delete.num_ep)) {
+			ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+			mausb_handle_ep_del_resp(dev,
+				&req->mgmt->ep_handle_delete,
+				&resp->mgmt->ep_handle_delete);
+		}
+		break;
+	case USBDevHandleReq:
+		req->mgmt->usb_dev_handle_req.dock_hub
+			= cpu_to_le16(mgmt->hub_dev_handle);
+		req->mgmt->usb_dev_handle_req.usb_rt_str
+			= cpu_to_le32(dev->dev->route);
+		req->mgmt->usb_dev_handle_req.speed =
+			cpu_to_le32(mausb_get_dev_speed(dev));
+		req->common->dev_handle = 0;
+
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+		hub = mausb_find_dev(ma_dev, dev->dev->parent, NULL, NULL);
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+		if (NULL != hub) {
+			/* This will work if the device is connected directly to
+			 * the dock, but not with a hub connected to the dock...
+			 * well... unless the hub in between is slower than high
+			 * speed. */
+			/* TODO: have the parent hub point to the proper hub for
+			 *       all conditions */
+			req->mgmt->usb_dev_handle_req.parent_hub =
+				hub->dev_handle;
+			req->mgmt->usb_dev_handle_req.parent_hub_port =
+				dev->dev->portnum;
+		} else {
+			/* parent_hub_port not set for SS */
+			mamgmt_dbg("%s: could not find parent hub at %p\n",
+				__func__, dev->dev->parent);
+		}
+
+		/* TODO: all the remaining fields */
+		req->mgmt->usb_dev_handle_req.mtt = 0;
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (resp && (NULL != dev))
+			dev->dev_handle =
+				le16_to_cpu(resp->mgmt->usb_dev_handle_resp);
+		break;
+
+	case DevResetReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case ModifyEP0Req:
+		if (NULL == ma_ep) {
+			mamgmt_err("%s: no ep0 for USB device at %p\n",
+				__func__, dev);
+		} else {
+			req->mgmt->modify_ep0_req.ep_handle = ma_ep->ep_handle;
+			req->mgmt->modify_ep0_req.max_pkt_size =
+				usb_endpoint_maxp(&ma_ep->ep->desc);
+		}
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		if (0 <= ret) {
+			if (SUCCESS == resp->common->pkt_status) {
+				if (resp->mgmt->modify_ep0_resp.ep_handle.handle) {
+					ma_ep->ep_handle = resp->mgmt->modify_ep0_resp.ep_handle;
+				}
+			} else
+				ret = -EIO;
+		}
+		break;
+	case SetUSBDevAddrReq:
+		/* TODO: verify timer value */
+		req->mgmt->set_dev_addr_req.resp_timeout =
+			cpu_to_le16(MAUSB_MGMT_RT_DELAY * (1000/HZ));
+
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+
+		if (0 <= ret) {
+			if (SUCCESS == resp->common->pkt_status) {
+				dev->dev_address =
+					le32_to_cpu(
+					resp->mgmt->set_dev_addr_resp.dev_addr);
+			} else
+				ret = -EIO;
+		}
+		break;
+	case UpdateDevReq:
+		break;
+	case USBDevDisconnectReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case DevDisconnectReq:
+		req->common->dev_handle = 0;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		break;
+	case SleepReq:         /* fallthrough */
+	case WakeReq:
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		/* not everyone supports power management yet */
+		/* if (SUCCESS != resp->common->pkt_status)
+			ret = -EBUSY; */
+		break;
+	case RemoteWakeReq:
+	case PingReq:
+	case DevInitDisconnectReq:
+	case SyncReq:
+		break;
+	case CancelTransferReq:
+		req->mgmt->cancel_transfer_req.ep_handle = ma_ep->ep_handle;
+		/* TODO: stream IDs (where applicable) */
+		req->mgmt->cancel_transfer_req.req_id =
+				ma_ep->state.active_request_id;
+		ret = internal_mausb_tx_mgmt_req(req, &resp, mgmt);
+		/* TODO: handle Responses */
+		break;
+	case USBDevResetReq:
+	case VendorSpecificReq:
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (resp != NULL)
+		mausb_free_pkt(resp);
+
+	spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	mausb_free_pkt(req);
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_tx_dev_mgmt_req_ep);
+
+/**
+ * Parses an incoming management packet resp.
+ *
+ * This function parses an incoming response packet and connects it to
+ * its associated request.
+ *
+ * @resp:	A pointer to the MA USB management response packet received.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt_resp(struct mausb_pkt *resp, struct mausb_mgmt *ma_mgmt)
+{
+	struct mausb_mgmt_req_list	*ma_mgmt_req;
+	unsigned long			irq_flags;
+
+	spin_lock_irqsave(ma_mgmt->ma_dev_lock, irq_flags);
+
+	list_for_each_entry(ma_mgmt_req, &ma_mgmt->req_list, req_list) {
+
+		/* if we found the request that triggered this response */
+		if (ma_mgmt_req->mgmt_req->mgmt->token == resp->mgmt->token) {
+			ma_mgmt_req->mgmt_resp = resp;
+
+			complete_all(&ma_mgmt_req->resp_rcvd);
+			spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+			return 0;
+		}
+	}
+
+	/* response given was not requested */
+	spin_unlock_irqrestore(ma_mgmt->ma_dev_lock, irq_flags);
+
+	mausb_free_pkt(resp);
+
+	return -EINVAL;
+}
+
+/**
+ * This function parses an incoming request packet and generates the
+ * appropriate response packet.
+ *
+ * @resp:	A pointer to the MA USB management request packet received.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt_req(struct mausb_pkt *req, struct mausb_mgmt *mgmt)
+{
+	int				ret;
+	struct mausb_pkt		*resp;
+	struct ma_dev			*ma_dev = mausb_mgmt_to_ma_dev(mgmt);
+	struct mausb_pkt_transfer	*transfer = &mgmt->tx_pair.to_ms;
+	unsigned long			irq_flags;
+
+	resp = mausb_alloc_pkt(MAUSB_PKT_TYPE_MGMT, &ret, GFP_ATOMIC);
+	if (!resp)
+		return -ENOMEM;
+
+	spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	ret = mgmt->req_switch(req->mgmt, resp->mgmt, mgmt);
+
+	if (ret >= 0) {
+		/* set the values common to all response packets */
+		resp->common->ver_flags |= MAUSB_VERSION_1_0;
+		/* type set above */
+		resp->common->length      = cpu_to_le16(mausb_pkt_length(resp));
+		/* device handle set above */
+		resp->common->ma_dev_addr = ma_dev->ma_dev_addr;
+		resp->common->mass_id     = ma_dev->mass_id;
+		/* pkt_status set above */
+		resp->mgmt->token         = req->mgmt->token;
+
+		mausb_pkt_fill_ms_pkt(resp, GFP_ATOMIC);
+		mamgmt_dbg("%s: sending %s packet\n", __func__,
+			mausb_type_to_string(resp->common->pkt_type));
+
+		spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+		transfer->transfer_packet(&resp->pkt, transfer->context);
+		spin_lock_irqsave(mgmt->ma_dev_lock, irq_flags);
+
+	} else {
+		/* we don't know how to handle this packet */
+		mamgmt_dbg("%s: packet type %s not supported\n", __func__,
+			mausb_type_to_string(resp->common->pkt_type));
+		mausb_free_pkt(resp);
+	}
+
+	spin_unlock_irqrestore(mgmt->ma_dev_lock, irq_flags);
+	return ret;
+}
+
+/**
+ * This function parses an incoming management packet, determines
+ * if it is a request or response, and passes the packet to the
+ * proper handler.
+ *
+ * @mgmt_pkt:	A pointer to the incoming MA USB management packet.
+ * @ma_mgmt:	The MA USB device's management structure.
+ */
+int mausb_rx_mgmt(struct mausb_pkt *mgmt_pkt, struct mausb_mgmt *mgmt)
+{
+	mamgmt_dbg("%s: %s packet received\n", __func__,
+		mausb_type_to_string(mgmt_pkt->common->pkt_type));
+
+	if (mausb_pkt_resp(mgmt_pkt))
+		return mausb_rx_mgmt_resp(mgmt_pkt, mgmt);
+	else
+		return mausb_rx_mgmt_req(mgmt_pkt, mgmt);
+}
+EXPORT_SYMBOL(mausb_rx_mgmt);
+
+/**
+ * Handles sent callback for management packets.
+ *
+ * Request packets are held until a response is received and should not be
+ * freed until then. Response packets can be freed as soon as they are sent out.
+ */
+void mausb_mgmt_pkt_sent(struct ms_pkt *ms_pkt)
+{
+	struct mausb_pkt *pkt;
+
+	pkt = ms_pkt_to_mausb_pkt(ms_pkt);
+
+	if (mausb_pkt_resp(pkt))
+		mausb_free_pkt(pkt);
+}
+EXPORT_SYMBOL(mausb_mgmt_pkt_sent);
+
diff --git a/drivers/staging/mausb/drivers/mausb_mgmt.h b/drivers/staging/mausb/drivers/mausb_mgmt.h
new file mode 100644
index 0000000..69ca13d
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_mgmt.h
@@ -0,0 +1,88 @@
+/* name:	mausb_mgmt.h
+ * description: Handles management packet structures and declarations common
+ *              to both hosts and devices.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_MGMT_H
+#define __MAUSB_MGMT_H
+
+#include "mausb_mem.h"
+#include "mausb_msapi.h"
+
+#ifdef DEBUG
+#define mamgmt_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define mamgmt_dbg(format, arg...)
+#endif
+
+#define mamgmt_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define mamgmt_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+struct ma_dev *mausb_mgmt_to_ma_dev(struct mausb_mgmt *mgmt);
+int mausb_tx_dev_mgmt_req(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host);
+int mausb_tx_dev_mgmt_req_ep(enum mausb_pkt_type type, struct mausb_mgmt *mgmt,
+		struct mausb_dev *dev, bool host, struct mausb_host_ep *ma_ep);
+int mausb_rx_mgmt(struct mausb_pkt *mgmt_pkt, struct mausb_mgmt *mgmt);
+void mausb_mgmt_pkt_sent(struct ms_pkt *pkt);
+int mausb_add_mgmt_channel(struct mausb_mgmt *mgmt, struct mausb_ms_drv *drv,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context),
+		void (*pkt_sent)(struct ms_pkt *pkt));
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 08/10] added media agnostic (MA) USB data packet handling
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (5 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

The MA USB Specification outlines packet types and a protocol for
bulk and interrupt transfers. This is where we implement that protocol.
MA USB transfers are initiated by the host via a TransferRequest packet.
The host then either sends data to the device via subsequent
TransferRequest packets (OUT transfer) or receives data from the device
via TransferResponse packets (IN transfer). Each data transfer is
identified by a Request ID number that increments up for each new transfer.
One URB maps to one MA USB transfer. A transfer can consist of one or
more MA USB packets depending on total transfer size. Each MA USB packet
is assigned a Sequence Number with sequence numbers incrementing up for
each new packet. The host sends a TransferAck packet to acknowledge the
end of a transfer or when requested to do so by the device.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/drivers/mausb_tx-device.c |  845 ++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tx-host.c   | 1209 +++++++++++++++++++++++
 drivers/staging/mausb/drivers/mausb_tx.c        |  316 ++++++
 drivers/staging/mausb/drivers/mausb_tx.h        |  127 +++
 4 files changed, 2497 insertions(+)
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-device.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx-host.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.c
 create mode 100644 drivers/staging/mausb/drivers/mausb_tx.h

diff --git a/drivers/staging/mausb/drivers/mausb_tx-device.c b/drivers/staging/mausb/drivers/mausb_tx-device.c
new file mode 100644
index 0000000..7d1cab2
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx-device.c
@@ -0,0 +1,845 @@
+/* Name:        mausb_tx_device.c
+ * Description: implements MA USB transfers on device side
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mausb_hcd.h"
+#include "mausb_udc.h"
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+
+#include <linux/kthread.h>
+
+int device_transfer_timeout(void *data)
+{
+	struct mausb_host_ep		*ep = (struct mausb_host_ep *) data;
+	struct mausb_udc		*udc = mausb_host_ep_to_maudc(ep);
+
+	while (!kthread_should_stop()) {
+		/*
+		 * make sure actual transfer timeout (i.e. not thread
+		 * setup)
+		 */
+		if (ep->tx_timed_out) {
+			if (ep->state.retry_counter > 0) {
+				maudc_dbg(udc, "%s: device timed out,"
+				      "  resending packet %i\n",
+				       __func__, ep->state.seq_number);
+
+				device_OUT_send_txResp(
+					&ep->active_transfer->state,
+					&ep->state,
+					ep->state.active_request_id,
+					ep->state.seq_number,
+					SUCCESS,
+					false, false, false);
+
+				ep->state.retry_counter--;
+			} else {
+				/*
+				 * TODO: start ping protocol per 5.2.2, if
+				 * successful reset timer and retries. For now
+				 * we just treat as if failed.
+				 */
+				ep->active_transfer->state.transfer_error =
+					true;
+				return -ETIMEDOUT;
+			}
+
+			ep->tx_timed_out = false;
+		}
+
+		/* put thread to sleep to wait for next timeout event */
+		wait_event_interruptible(ep->host_ep_wq,
+			kthread_should_stop() || ep->tx_timed_out);
+	}
+
+	return 0;
+}
+
+
+/*-------------------------IN transfer ------------------------*/
+
+/**
+ * Device-side IN transfer initialization process.
+ *
+ * @ tx_state:	Transfer state to be initialized.
+ * @ ep_state:	Endpoint state to be initialized.
+ * @ tx_req:	TransferReq packet from host that intiated transfer.
+ *
+ * Called every time a transferReq packet is received. Initializes transfer
+ * management variables.
+ */
+void device_init_IN_transfer(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	struct mausb_host_ep *ep = mausb_state_to_ep(ep_state);
+
+	tx_state->transfer_error = false;
+	tx_state->transfer_complete = false;
+	tx_state->rem_size = le32_to_cpu(tx_req->data->remaining_size_credit);
+
+	ep_state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+	ep_state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	ep_state->earliest_unacked = le32_to_cpu(tx_req->data->seq_num);
+	ep_state->active_request_id = tx_req->data->req_id;
+	ep_state->request_id++;
+
+	ep->actual_length = 0;
+
+	/* free old buffer if not previously freed */
+	if (ep->buffer)
+		kfree(ep->buffer);
+
+	/* alocate new buffer for this transfer */
+	ep->buffer = kzalloc(tx_state->rem_size, GFP_ATOMIC);
+}
+
+/* Determines if packet request id or sequence number is outside of the
+ * acceptable range
+ *
+ * Returns true if the packet sequence number or request id is invalid,
+ * otherwise returns false.
+ */
+bool is_invalid_IN_request(struct mausb_ep_state *ep_state,
+		struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	bool			invalid = false;
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(
+					mausb_state_to_ep(ep_state));
+
+	if ((ep_state->earliest_request_id - MAUSB_HALF_REQ_ID) <= r) {
+		if (r < ep_state->earliest_request_id) {
+			maudc_err(udc, "%s: too many outstanding requests\n",
+				__func__);
+			invalid = true;
+		}
+	}
+
+	if ((ep_state->earliest_unacked - MAUSB_HALF_SEQ_NUM) <= SN) {
+		if (SN < ep_state->earliest_unacked) {
+			maudc_err(udc, "%s: too many unacknowledged packets\n",
+				__func__);
+			invalid = true;
+		}
+	}
+
+	if (ep_state->seq_number < SN) {
+		if (SN < (ep_state->seq_number + MAUSB_HALF_SEQ_NUM)) {
+			maudc_err(udc, "%s: too many outstanding sequence"
+			       " numbers\n", __func__);
+			invalid = true;
+		}
+
+	}
+
+	return invalid;
+}
+
+/*
+ * transferReq reception process outlined in MA USB spec.
+ */
+int device_IN_rcvd_txReq(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN  = le32_to_cpu(tx_req->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	if (is_invalid_IN_request(ep_state, tx_req)) {
+		mausb_drop_packet(ep, tx_req);
+		device_IN_send_null_txResp(ep, ep_state->request_id,
+					   INVALID_REQUEST);
+	}
+
+	ep_state->earliest_unacked = SN;
+
+	if (tx_state->eot_detected && !tx_state->transfer_error) {
+		if (tx_state->last_transfer_sn < SN)
+			tx_state->transfer_complete = true;
+		else
+		ep_state->earliest_request_id = r;
+	}
+
+	if (r == ep_state->active_request_id && ep_state->delayed) {
+		maudc_dbg(udc, "%s: transfer %i is delayed, sending txResp with"
+		      " status = TRANSFER_PENDING\n", __func__, r);
+		device_IN_send_null_txResp(ep, r, TRANSFER_PENDING);
+	}
+
+	if (r == ep_state->request_id)
+		device_init_IN_transfer(tx_state, ep_state, tx_req);
+
+	return 0;
+}
+
+/* transferAck packet reception process for device side.
+ *
+ * @tx_state:	Transfer state variables for associated transfer.
+ * @ep_state:	Endpoint state variables for associated transfer.
+ * @tx_ack:	TransferAck packet being received.
+ *
+ * Called when device side driver receives a transferAck packet. Caller should
+ * verify that the request_id in the transferAck packet is valid before
+ * calling this function.
+ */
+int device_IN_ack_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_ack)
+{
+	int			ret = 0;
+	u8			r = tx_ack->data->req_id;
+	u8			u = ep_state->active_request_id;
+	u32			SN = le32_to_cpu(tx_ack->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+	bool			tx_complete = (!tx_state->transfer_error)
+					&& (tx_state->last_transfer_sn < SN);
+	bool			tx_complete_with_error =
+					(tx_state->transfer_error) && (u == r);
+	unsigned long		irq_flags = 0;
+
+	if (is_invalid_IN_request(ep_state, tx_ack))
+		tx_ack->data->common.pkt_status = DROPPED_PACKET;
+
+	switch (tx_ack->data->common.pkt_status) {
+	case DROPPED_PACKET:
+		maudc_dbg(udc, "%s: status = DROPPED_PACKET\n", __func__);
+		mausb_drop_packet(ep, tx_ack);
+		break;
+	case TRANSFER_PENDING:
+		maudc_dbg(udc, "%s: status = TRANSFER_PENDING\n", __func__);
+		if (r != ep_state->active_request_id)
+			mausb_drop_packet(ep, tx_ack);
+		/* else can start power saving measures */
+		break;
+	case MISSING_SEQUENCE_NUMBER:
+		maudc_dbg(udc, "%s: status = MISSING_SEQUENCE_NUMBER\n",
+			__func__);
+		mausb_resend_multi_packets(ep, &ep->resp_list,
+			le32_to_cpu(tx_ack->data->seq_num), irq_flags);
+		break;
+	case SUCCESS:
+		maudc_dbg(udc, "%s: status = SUCCESS\n", __func__);
+		ep_state->earliest_unacked = SN + 1;
+
+		if (tx_state->eot_detected) {
+			if (tx_complete || tx_complete_with_error)
+				tx_state->transfer_complete = true;
+			else
+				ep_state->earliest_request_id = u;
+
+			mausb_cleanup_ma_packets(ep,
+				le32_to_cpu(tx_ack->data->seq_num),
+				tx_ack->data->req_id);
+			kfree(ep->buffer);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* Submit a transferResp packet to host with no payload (used for errors).
+ *
+ * Per spec, sequence number field in a null transferResp packet is always
+ * reserved and set to 0
+ */
+int device_IN_send_null_txResp(struct mausb_host_ep *ep, u8 req_id, int status)
+{
+	struct mausb_pkt		*tx_resp;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+
+	tx_resp = mausb_create_dp(NULL, ep->active_transfer, MAUSB_IN,
+		MAUSB_DEV, GFP_ATOMIC);
+
+	if (!tx_resp)
+		return -ENOMEM;
+
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mausb_fill_pkt_ep(tx_resp, ep);
+
+	tx_resp->data->common.pkt_type = TransferResp;
+	tx_resp->data->req_id = req_id;
+	tx_resp->data->seq_num = 0;
+	tx_resp->buffer_length = 0;
+	tx_resp->data->remaining_size_credit = cpu_to_le32(tx_state->rem_size);
+	tx_resp->data->common.pkt_status = status;
+	tx_resp->common->length = cpu_to_le32(mausb_pkt_length(tx_resp));
+
+	mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+	return 0;
+}
+
+/**
+ * Submit a transferResp packet with payload to host (normal data transfer).
+ */
+int device_IN_send_txResp_with_payload(struct mausb_host_ep *ep)
+{
+	int				payload = 0;
+	int				max_buffer_length = 0;
+	int				ep_rem_size = ep->actual_length;
+	struct mausb_ep_state		*ep_state = &ep->state;
+	struct mausb_transfer_state	*tx_state = &ep->active_transfer->state;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_udc		*udc = mausb_host_ep_to_maudc(ep);
+
+	while (ep_rem_size > 0 || ep_state->seq_number == 0)  {
+
+		tx_resp = mausb_create_dp(NULL, ep->active_transfer, MAUSB_IN,
+					  MAUSB_DEV, GFP_ATOMIC);
+
+		if (!tx_resp)
+			return -ENOMEM;
+
+		list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+		mausb_fill_pkt_ep(tx_resp, ep);
+
+		tx_resp->data->common.pkt_type = TransferResp;
+		tx_resp->data->req_id = ep_state->active_request_id;
+		tx_resp->data->seq_num = cpu_to_le32(ep_state->seq_number);
+		tx_resp->data->remaining_size_credit =
+			cpu_to_le32(tx_state->rem_size);
+
+		max_buffer_length =
+			MAUSB_MAX_PACKET_SIZE - sizeof(tx_resp->data);
+
+		if (max_buffer_length <= 0) {
+			maudc_err(udc, "%s: packet buffer error: length"
+			       " = %i\n", __func__, max_buffer_length);
+		} else if (tx_state->rem_size <= 0) {
+			maudc_err(udc, "%s: packet buffer error: rem_size"
+			       " = %i\n", __func__, tx_state->rem_size);
+			ep->buffer = NULL;
+		} else {
+			payload = min_t(int, max_buffer_length,
+					ep_rem_size);
+		}
+
+		tx_resp->buffer = ep->buffer;
+		tx_resp->buffer_length = payload;
+		tx_resp->common->length = cpu_to_le16(mausb_pkt_length(tx_resp));
+
+		/* note: setting ARQ flag for error is optional */
+		if (tx_state->transfer_error) {
+			maudc_err(udc, "%s: transfer error with %i bytes "
+			       "remaining\n", __func__, tx_state->rem_size);
+
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+			tx_resp->data->common.pkt_status = UNSUCCESSFUL;
+
+			/*
+			 * TODO: take corrective action - e.g. clear all
+			 * transfers and restart endpoint
+			 */
+		}
+
+		tx_state->rem_size -= payload;
+		ep_rem_size -= payload;
+		/* note: setting ARQ flag for completion is optional */
+		if (tx_state->rem_size == 0 || ep_rem_size == 0) {
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+			tx_resp->data->common.pkt_status = SUCCESS;
+
+			ep_state->active_request_id++;
+		}
+
+		maudc_dbg(udc, "%s: sending transferResp packet with sequence"
+			" number %i for tranfer %i with %i bytes\n", __func__,
+			le32_to_cpu(tx_resp->data->seq_num),
+			le32_to_cpu(tx_resp->data->req_id), payload);
+
+		mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+		ep_state->seq_number++;
+
+	}
+
+	return 0;
+}
+
+/*------------------ protocol-managed OUT transfer --------------------*/
+
+bool should_drop_OUT_txReq(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state, struct mausb_pkt *tx_req)
+{
+	u8			r = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	int			payload_size = tx_req->buffer_length;
+	int			status = SUCCESS;
+	bool			drop = false;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	if (SN > ep_state->seq_number) {
+		maudc_err(udc, "%s: sequence number %i is too large "
+			"(expected < %i)\n", __func__, SN,
+			ep_state->seq_number);
+		drop = true;
+		status = MISSING_SEQUENCE_NUMBER;
+	} else if (SN < ep_state->seq_number) {
+		/* per spec, don't have to send response for this case */
+		maudc_err(udc, "%s: sequence number %i is too small "
+			"(expected >= %i)\n", __func__, SN,
+			ep_state->seq_number);
+		drop = true;
+	} else if (r < ep_state->earliest_request_id) {
+		maudc_err(udc, "%s: request ID %i is too small "
+			"(expected > %i)\n", __func__, r,
+			ep_state->earliest_request_id);
+		drop = true;
+		status = INVALID_REQUEST;
+	} else if (r > ep_state->request_id) {
+		/* account for wraparound */
+		if (ep_state->request_id != 0 && r != MAUSB_MAX_REQ_ID) {
+			maudc_err(udc, "%s: request ID %i is too large "
+				"(expected < %i)\n", __func__, r,
+				ep_state->request_id);
+			drop = true;
+			status = INVALID_REQUEST;
+		}
+	} else if ((payload_size + ep_state->occupancy)
+			> ep_state->rx_buf_size) {
+		maudc_err(udc, "%s: payload (%i bytes) is too large for buffer"
+			" (%i bytes)\n", __func__, payload_size,
+			ep_state->occupancy);
+		drop = true;
+		status = TRANSFER_DATA_BUFFER_ERROR;
+	}
+
+	/*
+	 * send txResp to host with appropriate status if txReq is going to
+	 * get dropped
+	 */
+	if (status) {
+		device_OUT_send_txResp(tx_state, ep_state,
+			ep_state->request_id, ep_state->seq_number, status,
+			false, false, false);
+	}
+
+	return drop;
+}
+
+/**
+ * Handles receipt of a transferRequest packet.
+ *
+ * @tx_state: State variables for associated transfer.
+ * @ep_state: State variables for associated device endpoint.
+ * @tx_req:   TransferRequest packet being received.
+ */
+int device_OUT_txReq_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	u8			req_id = tx_req->data->req_id;
+	u32			SN = le32_to_cpu(tx_req->data->seq_num);
+	int			ret = 0;
+	int			payload_size = tx_req->buffer_length;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	maudc_dbg(udc, "%s: received transferReq packet %i for transfer %i\n",
+		__func__, SN, req_id);
+
+	if (should_drop_OUT_txReq(ep_state, tx_state, tx_req)) {
+		maudc_err(udc, "%s: dropping packet %i\n", __func__, SN);
+		mausb_drop_packet(ep, tx_req);
+		return 0;
+	}
+
+	/* start new transfer */
+	if (req_id == (ep_state->request_id)) {
+		tx_state->transfer_error = false;
+		tx_state->transfer_complete = false;
+		tx_state->eot_detected = false;
+		tx_state->rem_size =
+			le32_to_cpu(tx_req->data->remaining_size_credit);
+		tx_state->payload_size = 0;
+		ep->active_transfer->transfer_size = tx_state->rem_size;
+		ep_state->active_request_id = req_id;
+		INIT_LIST_HEAD(&ep->req_list);
+		INIT_LIST_HEAD(&ep->resp_list);
+
+		ep->actual_length = 0;
+
+		ep_state->request_id =
+			mausb_req_id_add(ep_state->request_id, 1);
+	}
+
+	ep->buffer = tx_req->buffer;
+	ep_state->occupancy += payload_size;
+	ret = device_OUT_deliver_payload(tx_req, ep_state, tx_state);
+	ep_state->occupancy -= payload_size;
+
+	ep_state->seq_number++;
+
+	return 0;
+}
+
+/**
+ * Transmits a transferReq or transferAck packet.
+ */
+int device_OUT_send_txResp(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, u32 req_id, u32 seq_num,
+		int status, bool retry, bool eot, bool arq)
+{
+	struct mausb_host_ep *ep = mausb_state_to_ep(ep_state);
+	struct mausb_pkt *tx_resp = mausb_create_dp(NULL, ep->active_transfer,
+				     MAUSB_OUT, MAUSB_DEV, GFP_ATOMIC);
+	struct mausb_udc *udc = mausb_host_ep_to_maudc(ep);
+
+	if (!tx_resp)
+		return -ENOMEM;
+
+	mausb_fill_pkt_ep(tx_resp, ep);
+
+	tx_resp->data->common.pkt_type = TransferResp;
+	tx_resp->data->req_id = req_id;
+	tx_resp->data->seq_num = cpu_to_le32(seq_num);
+	tx_resp->data->common.pkt_status = status;
+	tx_resp->data->remaining_size_credit =
+		cpu_to_le32(ep_state->rx_buf_size - ep_state->occupancy);
+
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+
+	tx_resp->common->length = cpu_to_le16(mausb_pkt_length(tx_resp));
+
+	if (retry)
+		tx_resp->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+
+	if (eot)
+		tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+
+	if (arq)
+		tx_resp->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+
+	maudc_dbg(udc, "%s: sending transferResp packet %i for transfer %i\n",
+		__func__, le32_to_cpu(tx_resp->data->seq_num),
+		tx_resp->data->req_id);
+
+	/* send transferResp packet to host */
+	mausb_transfer_data_pkt(tx_resp, ep, GFP_ATOMIC);
+
+	return 0;
+}
+
+/**
+ * Handles receipt of a transferAck packet.
+ *
+ * Caller should ensure that transfer complete and error flags are not set.
+ * Note that what to do isn't defined in spec - we are on our own for this one!
+ */
+void device_OUT_ack_rcvd(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state,
+		struct mausb_pkt *tx_ack)
+{
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	maudc_dbg(udc, "%s: received transferAck packet for transfer %i\n",
+		__func__, tx_ack->data->req_id);
+
+	ep_state->occupancy = 0;
+	mausb_cleanup_ma_packets(ep, le32_to_cpu(tx_ack->data->seq_num),
+		tx_ack->data->req_id);
+}
+
+/*
+ * Copy payload from transferRequest into device buffer.
+ *
+ * @tx_req:   TransferRequest with payload to be delivered.
+ * @ep_state: State variables for associated device endpoint.
+ * @tx_state: State variables for associated transfer.
+ *
+ * Caller should ensure that transfer complete and error flags are not set.
+ * This function also includes payload delivery process outlined in spec.
+ */
+int device_OUT_deliver_payload(struct mausb_pkt *tx_req,
+		struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state)
+{
+	u32			req_sn = le32_to_cpu(tx_req->data->seq_num);
+	int			payload_size;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_udc	*udc = mausb_host_ep_to_maudc(ep);
+
+	/* payload delivery process */
+	payload_size = do_ma_transfer(ep, tx_req, MAUSB_OUT);
+
+	/* payload delivery confirmation process */
+	if (payload_size < 0) {
+		maudc_err(udc, "%s: transfer error %i\n", __func__,
+			payload_size);
+
+		device_OUT_send_txResp(tx_state, ep_state, tx_req->data->req_id,
+			le32_to_cpu(tx_req->data->seq_num), UNSUCCESSFUL,
+				       false, true, false);
+	}
+
+	else {
+		ep_state->earliest_unacked = req_sn + 1;
+		tx_state->payload_size = payload_size - tx_state->payload_size;
+		tx_state->rem_size =
+			le32_to_cpu(tx_req->data->remaining_size_credit);
+		tx_state->payload_size = payload_size;
+
+		maudc_dbg(udc, "%s: delivered %i bytes with %i remaining\n",
+		       __func__, payload_size, tx_state->rem_size);
+
+		/* control response packet */
+		if (tx_req->setup) {
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, true, true);
+
+		/* end of transfer response packet */
+		} else if (tx_state->rem_size == 0) {
+			tx_state->last_transfer_sn = req_sn;
+
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, true, true);
+		} else if (tx_req->data->eps_tflags & MAUSB_PKT_TFLAG_ARQ) {
+			device_OUT_send_txResp(tx_state, ep_state,
+				tx_req->data->req_id,
+				le32_to_cpu(tx_req->data->seq_num),
+				SUCCESS, false, false, true);
+		}
+	}
+
+	return 0;
+}
+
+/*------------------ transfer interfaces ----------------------------*/
+
+/**
+ * Called to receive both transferRequest and transferAck packets.
+ * For transferRequests, a new transfer is initiated - transfer state values
+ * are initialized and a request is send to the device to get data. For
+ * transferAcks, a transfer is ended (either successfully or with error,
+ * depending on transferAck packet status).
+ */
+int receive_ma_packet_IN(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	list_add_tail(&pkt->pkt_list, &ep->req_list);
+
+	udc = mausb_host_ep_to_maudc(ep);
+
+	if (mausb_is_a_retry(ep, &ep->resp_list, pkt))
+		return 0;
+
+	switch (pkt->data->common.pkt_type) {
+	case TransferReq:
+		maudc_dbg(udc, "%s: received transferReq %i for transfer %i\n",
+			__func__, le32_to_cpu(pkt->data->seq_num),
+			pkt->data->req_id);
+		device_IN_rcvd_txReq(&ep->state, &ep->active_transfer->state,
+			pkt);
+		ret = do_ma_transfer(ep, pkt, MAUSB_IN);
+		ret = device_IN_send_txResp_with_payload(ep);
+		break;
+	case TransferAck:
+		maudc_dbg(udc, "%s: received transferAck for transfer %i\n",
+			__func__, pkt->data->req_id);
+		ret = device_IN_ack_rcvd(&ep->active_transfer->state,
+			&ep->state, pkt);
+		break;
+	default:
+		maudc_err(udc, "%s: invalid packet type/subtype %i\n",
+			__func__, pkt->data->common.pkt_type);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * Receives both transferReq and transferAck packets for OUT transfers. When a
+ * packet is received, it is put on a list for handling. If the endpoint is not
+ * already handling a packet, it starts iterating through the list of received
+ * packets.
+ */
+int receive_ma_packet_OUT(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	list_add_tail(&pkt->pkt_list, &ep->req_list);
+
+	udc = mausb_host_ep_to_maudc(ep);
+
+	if (mausb_is_a_retry(ep, &ep->resp_list, pkt))
+		return 0;
+
+	/* determine if packet is a transferRequest */
+	if (pkt->data->common.pkt_type == TransferReq) {
+		maudc_dbg(udc, "%s: received transferReq %i for transfer %i\n",
+			__func__, le32_to_cpu(pkt->data->seq_num),
+			pkt->data->req_id);
+		ret = device_OUT_txReq_rcvd(&ep->active_transfer->state,
+			&ep->state, pkt);
+
+	/* if not a transferReq, it should be a transferAck */
+	} else if (pkt->data->common.pkt_type == TransferAck) {
+		maudc_dbg(udc, "%s: received transferAck for transfer %i\n",
+			__func__, pkt->data->req_id);
+		device_OUT_ack_rcvd(&ep->active_transfer->state, &ep->state,
+			pkt);
+	} else {
+		/* TODO: deal with invalid packet type */
+	}
+
+	return ret;
+}
+
+/**
+ * Called when a transferReq is received on a control endpoint.
+ *
+ * @ms_pkt:	Packet being received.
+ * @context:	Device endpoint associated with transfer (this should always
+ *		be ep0).
+ */
+int receive_ma_packet_control(struct ms_pkt *ms_pkt, void *context)
+{
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*pkt;
+	struct mausb_udc		*udc;
+
+	if ((NULL == context) || (NULL == ms_pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	del_timer(&ep->timer);
+
+	pkt = mausb_pkt_from_ms_pkt_ep(ms_pkt, ep, GFP_ATOMIC);
+	udc = mausb_host_ep_to_maudc(ep);
+
+	/*
+	 * A new control transfer begins with a transfer request carrying setup
+	 * data and sequence number 0.
+	 */
+	if (pkt->setup) {
+		ep->state.seq_number = 0;
+		ep->actual_length = 0;
+		ep->active_transfer->state.rem_size =
+			le32_to_cpu(pkt->data->remaining_size_credit);
+
+		/*
+		 * Determine if this is a control IN or OUT - if there is data
+		 * in the packet, or the host is requesting no data, we are
+		 * an OUT.
+		 */
+		if (0 != pkt->buffer_length ||
+		    0 == le32_to_cpu(pkt->data->remaining_size_credit)) {
+
+			ep->control_dir = MAUSB_OUT;
+
+		} else
+			ep->control_dir = MAUSB_IN;
+	}
+
+	kfree(pkt);
+	pkt = NULL;
+
+	if (MAUSB_IN == ep->control_dir)
+		ret = receive_ma_packet_IN(ms_pkt, context);
+	else
+		ret = receive_ma_packet_OUT(ms_pkt, context);
+
+	return ret;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_tx-host.c b/drivers/staging/mausb/drivers/mausb_tx-host.c
new file mode 100644
index 0000000..94b9e25
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx-host.c
@@ -0,0 +1,1209 @@
+/* Name:        mausb_tx-host.c
+ * Description: implement host-side Ma USB transfers
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kthread.h>
+
+#include "mausb_hcd.h"
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+
+/**
+ * Handles a data transfer timeout event, then sleeps until the next
+ * timeout event. Timeout events that wish to use this thread should
+ * set the ep->tx_timed_out flag to true to ensure that the thread
+ * is woken.
+ */
+int host_transfer_timeout(void *data)
+{
+	int				err = 0;
+	int				dir_in = 0;
+	int				seq_num = 0;
+	struct mausb_host_ep		*ep = (struct mausb_host_ep *) data;
+	struct mausb_ep_state		*ep_state = &ep->state;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_pkt		*tx_req;
+	unsigned long			irq_flags;
+	struct mausb_hcd		*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	while (!kthread_should_stop()) {
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		/*
+		 * make sure there is an active transfer for timeout
+		 * to handle (i.e. not thread creation/initialization)
+		 */
+		if (ep->active_transfer && ep->active_transfer->urb) {
+			tx_state = &ep->active_transfer->state;
+			dir_in = usb_pipein(ep->active_transfer->urb->pipe);
+
+			seq_num = ep_state->earliest_unacked;
+
+			if (ep_state->retry_counter >  0) {
+				mausb_dbg(mhcd, "%s: host timed out waiting"
+					" for pkt %i\n", __func__, seq_num);
+
+				/* see if we have corresponding request */
+				err = mausb_resend_multi_packets(ep,
+					&ep->req_list, seq_num, irq_flags);
+
+				/* if not, send new req */
+				if (err != 0) {
+					spin_unlock_irqrestore(&ep->ep_lock,
+								irq_flags);
+
+					tx_req = mausb_create_dp(NULL,
+						 ep->active_transfer,
+						 MAUSB_IN, MAUSB_HOST,
+						 GFP_ATOMIC);
+
+					tx_req->data->common.pkt_type =
+						TransferReq;
+					tx_req->data->seq_num = seq_num;
+					tx_req->data->common.pkt_status =
+						SUCCESS;
+					tx_req->data->req_id =
+						ep_state->active_request_id;
+					tx_req->common->ver_flags
+						|= MAUSB_PKT_FLAG_RETRY;
+					tx_req->common->length =
+						mausb_pkt_length(tx_req);
+
+					/* submit packet for transport */
+					mausb_transfer_data_pkt(tx_req, ep,
+								GFP_ATOMIC);
+
+					spin_lock_irqsave(&ep->ep_lock,
+								irq_flags);
+
+					list_add_tail(&tx_req->pkt_list,
+						      &ep->req_list);
+				}
+
+				ep_state->retry_counter--;
+			} else {
+				/*
+				 * Can optionally initiate ping process in sec
+				 * 5.2.3 of spec. For now we just treat as if
+				 * ping protocol failed. */
+				tx_state->transfer_error = true;
+
+				spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+				mausb_unlink_giveback_urb(ep->active_transfer,
+							  -ETIMEDOUT);
+				spin_lock_irqsave(&ep->ep_lock, irq_flags);
+			}
+		}
+
+		ep->tx_timed_out = false;
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		/* put thread to sleep to wait for next timeout event */
+		wait_event_interruptible(ep->host_ep_wq,
+			kthread_should_stop() || ep->tx_timed_out);
+	}
+
+	return 0;
+}
+
+/* Initialize transfer state, for beginning a new transfer */
+static void mausb_host_init_tx_state(struct mausb_transfer_state *tx_state,
+		u32 tx_size)
+{
+	tx_state->transfer_error = false;
+	tx_state->transfer_complete = false;
+	tx_state->eot_detected = false;
+	tx_state->transfer_acked = false;
+	tx_state->rem_size = tx_size;
+	tx_state->payload_size = 0;
+}
+
+/*--------------------- IN transfers ------------------------------*/
+
+/**
+ * Host-side IN transfer initialization process.
+ *
+ * @tx_state: Transfer state to be initialized.
+ * @ep_state: Endpoint state to be initialized.
+ * @maurb:    maurb associated with transfer.
+ *
+ * Called whenever a new IN transfer is initiated by the host.
+ * Initializes transfer state variables, resets timers, then submits a
+ * transferReq packet to the device side driver. After successful submission
+ * of a transferReq packet, the transfer request id is incremented by one
+ * for the next transfer. When transfer request id reaches its max value,
+ * it wraps back around to zero (per mausb spec requirements).
+ */
+void host_init_IN_transfer(struct mausb_transfer_state *tx_state,
+		struct mausb_host_ep *ep, struct mausb_urb *maurb)
+{
+	int			status = SUCCESS;
+	u32			tx_size = maurb->urb->transfer_buffer_length;
+	unsigned long		irq_flags;
+	struct mausb_ep_state	*ep_state = &ep->state;
+	struct mausb_pkt	*tx_req = mausb_create_dp(&status, maurb,
+					MAUSB_IN, MAUSB_HOST, GFP_ATOMIC);
+
+	if (!tx_req)
+		return;
+
+	mausb_fill_pkt_ep(tx_req, ep);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* fill the transfer request */
+	tx_req->data->common.pkt_type = TransferReq;
+	tx_req->data->remaining_size_credit =
+		maurb->urb->transfer_buffer_length;
+	tx_req->data->req_id = ep_state->request_id;
+	tx_req->data->seq_num = cpu_to_le32(ep_state->seq_number);
+
+	if (mausb_pkt_has_setup_data(tx_req->data)) {
+		tx_req->setup =
+			(struct usb_ctrlrequest *) maurb->urb->setup_packet;
+	}
+
+	tx_req->common->length = mausb_pkt_length(tx_req);
+
+	/* set the transfer state */
+	mausb_host_init_tx_state(tx_state, tx_size);
+
+	/* set the endpoint state */
+	ep->tx_timed_out = false;
+	ep_state->active_request_id = ep_state->request_id;
+	ep_state->keep_alive_timer = MAUSB_TRANSFER_TIMEOUT;
+	ep_state->retry_counter = MAUSB_BULK_TRANSFER_RETRIES;
+	ep_state->request_id = mausb_req_id_add(ep_state->request_id, 1);
+
+	/* send the packet */
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	host_IN_txReq_transmit(tx_req, ep, tx_state);
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* start timeout timer */
+	mod_timer(&ep->timer,
+	jiffies + msecs_to_jiffies(ep_state->keep_alive_timer));
+
+	/* add the packet to the endpoint */
+	list_add_tail(&tx_req->pkt_list, &ep->req_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+}
+
+/**
+* Releases an MA USB packet to the data channel and updates state.
+*/
+void host_IN_txReq_transmit(struct mausb_pkt *tx_req, struct mausb_host_ep *ep,
+		struct mausb_transfer_state *tx_state)
+{
+	int			ret;
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	mausb_dbg(mhcd, "%s: sending pkt %i for request %i\n", __func__,
+		  le32_to_cpu(tx_req->data->seq_num), tx_req->data->req_id);
+
+	/* submit packet for transport */
+	ret = mausb_transfer_data_pkt(tx_req, ep, GFP_ATOMIC);
+
+	if (tx_state->eot_detected && !tx_state->transfer_error)
+		if (tx_state->last_transfer_sn
+			< le32_to_cpu(tx_req->data->seq_num)) {
+			tx_state->transfer_acked = true;
+		/* TODO:transfer_completion_timer = aMaxTransferLifetime */
+		}
+}
+
+/**
+ * Transmits a TransferAck packet.
+ *
+ * @tx_state: State information associated with this transfer.
+ * @in:	      Set to true for an IN transfer.
+ * @ep_state: State information associated with transfer endpoint.
+ * @status:   Status to fill transferAck packet status field.
+ *	      Note: unless otherwise specified in spec, should be SUCCESS.
+ * @seq_num:  Sequence number to fill transferAck packet sequence number field.
+ *	      Note: should be the greatest sequence number of the packets to
+ *	      be acked.
+ *
+ * Called to acknowledge end of transfer or when a packet that otherwise
+ * requires acknowledgement (i.e. ARQ flag is set) is received.
+ */
+int host_send_ack(struct mausb_transfer_state *tx_state, bool in,
+		struct mausb_ep_state *ep_state, int status, u32 seq_num)
+{
+	struct mausb_urb	*maurb = container_of(tx_state,
+					struct mausb_urb, state);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_pkt	*tx_ack = mausb_create_dp(NULL, maurb, in,
+					MAUSB_HOST, GFP_ATOMIC);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	if (tx_ack == NULL)
+		return -ENOMEM;
+
+	mausb_fill_pkt_ep(tx_ack, ep);
+
+	tx_ack->data->common.pkt_type = TransferAck;
+	tx_ack->data->seq_num = cpu_to_le32(seq_num);
+	tx_ack->data->common.pkt_status = status;
+	tx_ack->data->req_id = ep_state->active_request_id;
+	tx_ack->common->length = cpu_to_le16(mausb_pkt_length(tx_ack));
+
+	mausb_dbg(mhcd, "%s: sending ack for transfer %i\n",
+	       __func__, ep_state->active_request_id);
+
+	if (in && tx_state->eot_detected) {
+		if (mausb_transfer_is_complete(tx_state, seq_num)) {
+			tx_state->transfer_acked = true;
+			/* TODO: set completion timer */
+		}
+
+		/* since we're done, clear out packet lists and free memory */
+		mausb_cleanup_ma_packets(ep, seq_num,
+			 ep_state->earliest_request_id);
+
+	} else if (!in) {
+		tx_state->transfer_acked = true;
+		/* TODO: set transfer completion timer = aMaxTransferLifetime */
+	}
+
+	/* submit packet for transport */
+	mausb_transfer_data_pkt(tx_ack, ep, GFP_ATOMIC);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	list_add_tail(&tx_ack->pkt_list, &ep->req_list);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Deliver payload from transferResp to target urb.
+ *
+ * @tx_resp:	transferResponse packet with data to be transfered.
+ * @maurb:	urb associated with transfer.
+ *
+ * Must ensure that transfer has not been completed (transfer_complete is
+ * false) and there are no transfer errors (transfer_error is false) before
+ * calling.
+ *
+ * Returns length in bytes of data delivered.
+ */
+int host_IN_deliver_payload(struct mausb_pkt *tx_resp, struct mausb_urb *maurb)
+{
+	int			offset;
+	int			length = tx_resp->buffer_length;
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(maurb->ep);
+
+	if (length == 0) {
+		mausb_err(mhcd, "%s: no payload (length = 0)\n", __func__);
+		return length;
+	}
+
+	if (!maurb || !maurb->urb || !maurb->urb->transfer_buffer) {
+		mausb_err(mhcd, "%s: urb not found\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!tx_resp || !tx_resp->buffer) {
+		mausb_err(mhcd, "%s: no transferResponse buffer\n", __func__);
+		return -EINVAL;
+	}
+
+	offset = maurb->urb->transfer_buffer_length - maurb->state.rem_size;
+
+	memcpy(maurb->urb->transfer_buffer + offset, tx_resp->buffer, length);
+
+	maurb->urb->actual_length += length;
+
+	return length;
+}
+
+/**
+ * Determines if a received transfer response should be dropped
+ * due to invalid request or sequence number. Note: this fuction does not
+ * actually drop any packets.
+ *
+ * The caller should be holding the endpoints spinlock.
+ *
+ * Returns true if packet should be dropped, otherwise returns false.
+ */
+bool should_drop_txResp(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp, bool in)
+{
+	bool			drop = false;
+	u8			r = tx_resp->data->req_id;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	/* transfer is complete or error flag is set */
+	if (tx_state->transfer_complete || tx_state->transfer_error) {
+		mausb_err(mhcd, "%s: transfer %i already completed %s error\n",
+			__func__, r,
+			(tx_state->transfer_error ? "with" : "without:"));
+		drop = true;
+	}
+
+	/* request id is invalid */
+	if (mausb_req_id_lt(r, ep_state->earliest_request_id) ||
+		(mausb_req_id_gt_eq(r, ep_state->request_id))) {
+
+		mausb_err(mhcd, "%s: request ID %i is invalid\n", __func__, r);
+
+		host_send_ack(tx_state, MAUSB_IN, ep_state,
+			INVALID_REQUEST, SN);
+		drop = true;
+	}
+
+	/*
+	 * Sequence number is reserved for TRANSFER_PENDING,
+	 * so skip sequence number checks.
+	 */
+	if (TRANSFER_PENDING == tx_resp->common->pkt_status)
+		return drop;
+
+	/* sequence number is larger than expected */
+	if (mausb_seq_num_gt(SN, ep_state->seq_number)) {
+
+		mausb_err(mhcd, "%s: missing sequence number - expected %i but"
+			" received %i\n", __func__, ep_state->seq_number, SN);
+
+		drop = true;
+		host_send_ack(tx_state, MAUSB_IN, ep_state,
+			MISSING_SEQUENCE_NUMBER, ep_state->seq_number);
+	}
+
+	/* sequence number is invalid */
+	if ((!in && mausb_seq_num_lt(SN, ep_state->earliest_unacked)) ||
+		(in && mausb_seq_num_lt(SN, ep_state->seq_number))) {
+
+		mausb_err(mhcd, "%s: invalid sequence number %i for %s"
+			" transfer\n", __func__, SN, (in ? "IN" : "OUT"));
+		drop = true;
+	}
+
+	return drop;
+}
+
+/**
+ * Handles receipt of transferResp.
+ *
+ * @ep_state: State information associated with transfer endpoint.
+ * @tx_state: State information associated with transfer.
+ * @tx_resp:  transferResponse packet being received.
+ *
+ * Called when host receives a transferResp packet from a device during an IN
+ * transfer. Updates host-side transfer and endpoint states and checks for
+ * packet errors.
+ *
+ * Returns length of payload copied into host buffer. If nothing was copied
+ * returns 0 or errno if error.
+ */
+int host_IN_txResp_rcvd(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp)
+{
+	int			length = 0;
+	u8			r = tx_resp->data->req_id;
+	u8			eps_flags = tx_resp->data->eps_tflags;
+	u32			payload_size = tx_resp->buffer_length;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+
+	/* look for sequence number and request ID errors */
+	if (should_drop_txResp(ep_state, tx_state, tx_resp, MAUSB_IN)) {
+		mausb_drop_packet(ep, tx_resp);
+		return length;
+	}
+
+	switch (tx_resp->data->common.pkt_status) {
+	case DROPPED_PACKET:
+		mausb_dbg(mhcd, "%s: status = DROPPED_PACKET\n", __func__);
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	case INVALID_REQUEST: /* same as MISSING_REQUEST_ID in spec */
+		mausb_dbg(mhcd, "%s: status = INVALID_REQUEST\n", __func__);
+		/*
+		 * TODO: invalidate all outstanding transferReqs with req id
+		 * from r to ep_state->request_id - 1
+		 */
+		ep_state->request_id = r;
+		break;
+	case TRANSFER_PENDING:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_PENDING\n", __func__);
+		ep_state->keep_alive_timer =
+			(tx_state->k * MAUSB_TRANSFER_KEEP_ALIVE);
+		ep_state->retry_counter = ep_state->transfer_retries;
+		if (eps_flags & MAUSB_PKT_TFLAG_ARQ) {
+			/*
+			 * NOTE: per spec, the sequence number in the ack packet
+			 * is reserved and set to 0.
+			 */
+			host_send_ack(tx_state, MAUSB_IN, ep_state,
+				TRANSFER_PENDING, 0);
+		}
+		break;
+	case TRANSFER_EP_STALL:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_EP_STALL\n", __func__);
+		if (eps_flags & MAUSB_PKT_TFLAG_EOT) {
+			host_send_ack(tx_state, MAUSB_IN, ep_state,
+				      TRANSFER_EP_STALL, SN);
+
+			tx_state->eot_detected = true;
+		}
+		break;
+	case SUCCESS:
+		ep_state->keep_alive_timer = MAUSB_TRANSFER_KEEP_ALIVE;
+		ep_state->transfer_retries = MAUSB_BULK_TRANSFER_RETRIES;
+
+		if (SN == ep_state->seq_number) {
+			if (tx_state->rem_size >= payload_size) {
+				length = host_IN_deliver_payload(tx_resp,
+					 container_of(tx_state,
+						struct mausb_urb, state));
+
+				ep_state->seq_number++;
+				tx_state->rem_size -= length;
+
+				if (eps_flags & MAUSB_PKT_TFLAG_ARQ ||
+					eps_flags & MAUSB_PKT_TFLAG_EOT) {
+					host_send_ack(tx_state, MAUSB_IN,
+						ep_state, SUCCESS, SN);
+				}
+
+				if (eps_flags & MAUSB_PKT_TFLAG_EOT) {
+					tx_state->eot_detected = true;
+					tx_state->last_transfer_sn = SN;
+					ep_state->earliest_request_id =
+						mausb_req_id_add(
+						ep_state->earliest_request_id,
+						1);
+					ep_state->active_request_id =
+						mausb_req_id_add(
+						ep_state->active_request_id, 1);
+
+					/*
+					 * Can optionally send ack here.
+					 * If don't send ack, next txReq
+					 * serves as ack.
+					 */
+
+					if (tx_state->rem_size > 0) {
+						tx_state->transfer_error = true;
+						mausb_dbg(mhcd, "%s: end of "
+						"transfer with %i bytes left\n",
+						__func__, tx_state->rem_size);
+					}
+				}
+			} else {
+				/*
+				 * For now just drop packet, but can also
+				 * optionally admit up to rem_size of payload
+				 * into buffer.
+				 */
+				tx_state->transfer_error = true;
+				mausb_drop_packet(ep, tx_resp);
+				host_send_ack(tx_state, MAUSB_IN, ep_state,
+						 TRANSFER_SIZE_ERROR, SN);
+			}
+		}
+		break;
+	default:
+		mausb_dbg(mhcd, "%s: status = %i, dropping packet\n",
+		       __func__, tx_resp->data->common.pkt_status);
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	}
+
+	return length;
+}
+
+
+/*------------------ protocol-managed OUT transfers -----------------*/
+
+/**
+ * @ tx_state: Transfer state to be initialized.
+ * @ ep:       Endpoint associated with transfer.
+ * @ tx_size:  Transfer size in bytes.
+ *
+ * Called every time a new OUT transfer is initiated. Initializes transfer
+ * state variables.
+ */
+void host_init_OUT_transfer(struct mausb_transfer_state *tx_state,
+	struct mausb_host_ep *ep, u32 tx_size)
+{
+	unsigned long irq_flags;
+
+	mausb_host_init_tx_state(tx_state, tx_size);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	ep->tx_timed_out = false;
+
+	ep->state.active_request_id = ep->state.request_id;
+
+	/*
+	 * Increment request id for new transfer (or go back to zero
+	 * if max sequence number is reached.
+	 */
+	ep->state.request_id = mausb_req_id_add(ep->state.request_id, 1);
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+}
+
+/**
+ * Send a transferReq packet to a device.
+ *
+ * @tx_state:     State variables for transfer.
+ * @ep_state:     State variables for endpoint associated with transfer.
+ * @tx_req;	  MA USB transferReq packet to be sent out.
+ */
+int host_OUT_send_txReq(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_pkt *tx_req)
+{
+	int			i = 0;
+	int			payload_size = tx_req->buffer_length;
+	int			mausb_pkt_head_size;
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	mausb_pkt_head_size = mausb_pkt_header_length(tx_req->common);
+
+	if (payload_size > ep_state->rx_buf_size) {
+		mausb_dbg(mhcd, "%s: payload of %i bytes is too big - device "
+		       "can only receive %i bytes\n", __func__, payload_size,
+		       ep_state->rx_buf_size);
+		while (payload_size > ep_state->rx_buf_size &&
+		       i <= MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT) {
+			msleep(1);
+			i++;
+		}
+		if (i > MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT) {
+			mausb_dbg(mhcd,
+				"wait gadget receive buffer free time out\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	if (mausb_seq_num_lt(ep_state->seq_number,
+				ep_state->earliest_unacked)) {
+
+		mausb_err(mhcd, "%s: too many outstanding packets\n",
+		       __func__);
+		/* TODO: transmit packet at later time (flow control) */
+	}
+
+	if (payload_size <= ep_state->rx_buf_size) {
+		/*
+		 * Credit remains less than 1 max_packet_payload,
+		 * and there are more than 1 max_packet_payload data to
+		 * transfer. Ask device to update credit.
+		 */
+		if (ep_state->rx_buf_size - payload_size <
+		    MAUSB_MAX_PACKET_SIZE - mausb_pkt_head_size  &&
+		    tx_state->rem_size > ep_state->rx_buf_size - payload_size) {
+			mausb_dbg(mhcd, "request ARQ, payload_size: %d,"
+				" rx_buf_size: %d\n", payload_size,
+				ep_state->rx_buf_size);
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+		}
+		/* look for end of transfer */
+		if (tx_state->rem_size == 0) {
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_EOT;
+			tx_req->data->eps_tflags |= MAUSB_PKT_TFLAG_ARQ;
+		}
+
+		/* set timer if expecting a response */
+		if (tx_req->data->eps_tflags & MAUSB_PKT_TFLAG_ARQ &&
+		    le32_to_cpu(tx_req->data->seq_num) != 0) {
+			tx_state->ack_transfer_sn =
+				le32_to_cpu(tx_req->data->seq_num);
+			mod_timer(&ep->timer, jiffies +
+				msecs_to_jiffies(MAUSB_TRANSFER_TIMEOUT));
+		}
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		tx_req->common->length = cpu_to_le16(mausb_pkt_length(tx_req));
+
+		mausb_dbg(mhcd, "%s: sending transferRequest with sequence"
+			" number %i for request %i with %i bytes of payload\n",
+			__func__, le32_to_cpu(tx_req->data->seq_num),
+			le32_to_cpu(tx_req->data->req_id),
+			tx_req->buffer_length);
+
+		tx_state->payload_size += payload_size;
+
+		/* submit packet for transport */
+		mausb_transfer_data_pkt(tx_req, ep, GFP_ATOMIC);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+		ep_state->rx_buf_size -= payload_size;
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return 0;
+}
+
+/**
+ * Determines if this urb is a for a control transfer. For host side only
+ * (device doesn't have urbs).
+ */
+static bool mausb_control_xfer(struct mausb_urb *maurb)
+{
+	return (usb_endpoint_type(&maurb->urb->ep->desc) ==
+		USB_ENDPOINT_XFER_CONTROL && maurb->urb->setup_packet);
+}
+
+/**
+ * Create and send OUT transferRequest packets for a given transfer.
+ *
+ * @tx_state:	State associated with transfer.
+ * @ep_state:	State associated with transfer endpoint.
+ * @maurb:	MA USB urb associated with transfer.
+ */
+int host_OUT_generate_txReqs(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, struct mausb_urb *maurb)
+{
+	int				offset = 0;
+	int				pkt_length = 0;
+	int				payload_size = 0;
+	int				max_buffer_length = 0;
+	struct				mausb_pkt *tx_req;
+	struct mausb_host_ep		*ep = mausb_state_to_ep(ep_state);
+	struct mausb_hcd		*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long irq_flags;
+
+	/*
+	 * Always generate at least one OUT transferReq (OUT control
+	 * transfers may only contain setup data).
+	 */
+	do {
+		/* create transferReq and set packet field values */
+		tx_req = mausb_create_dp(SUCCESS, maurb, MAUSB_OUT,
+					 MAUSB_HOST, GFP_ATOMIC);
+
+		if (!tx_req)
+			return -ENOMEM;
+
+		mausb_fill_pkt_ep(tx_req, ep);
+		tx_req->data->common.pkt_type = TransferReq;
+		tx_req->data->req_id = ep_state->active_request_id;
+		tx_req->data->seq_num = cpu_to_le32(ep_state->seq_number);
+		tx_req->data->remaining_size_credit =
+			cpu_to_le32(tx_state->rem_size);
+		tx_req->buffer_length = 0;
+		tx_req->nents = 0;
+
+		/* add setup data (If necessary) */
+		if (mausb_pkt_has_setup_data(tx_req->data)) {
+			tx_req->setup = (struct usb_ctrlrequest *)
+						maurb->urb->setup_packet;
+		}
+
+		/* calculate max packet buffer size */
+		pkt_length = mausb_pkt_length(tx_req);
+		max_buffer_length = MAUSB_MAX_PACKET_SIZE - pkt_length;
+		payload_size = min_t(int, max_buffer_length,
+				     tx_state->rem_size);
+
+		/* a control transfer can be empty, but nothing else */
+		if (payload_size <= 0 &&
+				!mausb_pkt_has_setup_data(tx_req->data)) {
+			mausb_err(mhcd, "%s: packet error - no room for "
+			       "payload (buffer size is %i)\n", __func__,
+			       payload_size);
+			return -ENOBUFS;
+		} else if (payload_size > 0) {
+
+			if (!maurb->urb->transfer_buffer) {
+				mausb_err(mhcd, "%s: no transfer buffer\n",
+				__func__);
+			}
+
+			/* create packet buffer and fill */
+			tx_req->buffer = maurb->urb->transfer_buffer + offset;
+			if (!tx_req->buffer) {
+				mausb_free_pkt(tx_req);
+				return -ENOMEM;
+			}
+
+			tx_req->buffer_length = payload_size;
+		}
+
+		/* update state variables */
+		offset += payload_size;
+		tx_state->rem_size -= payload_size;
+		tx_req->data->remaining_size_credit = tx_state->rem_size;
+
+		/* send transferReq packet to device */
+		host_OUT_send_txReq(tx_state, ep_state, tx_req);
+
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+		ep_state->seq_number =
+				mausb_seq_num_add(ep_state->seq_number, 1);
+		list_add_tail(&tx_req->pkt_list, &ep->req_list);
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	} while (tx_state->rem_size > 0);
+
+	return 0;
+}
+
+/**
+ * Updates transfer and endpoint states after a transferResp is received.
+ *
+ * @ep_state: State information for enpoint associated with transfer.
+ * @tx_state: State information for transfer in progress.
+ * @tx_resp:  transferResponse packet that has been received.
+ *
+ * Called whenever a transferResp packet is received. Returns size in bytes
+ * of payload transferred.
+ */
+int host_OUT_txResp_rcvd(struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state,
+		struct mausb_pkt *tx_resp)
+{
+	int			payload_size = 0;
+	u8			status = tx_resp->common->pkt_status;
+	u8			ep_flags = tx_resp->data->eps_tflags;
+	u32			SN = le32_to_cpu(tx_resp->data->seq_num);
+	u32			credit = le32_to_cpu(
+					tx_resp->data->remaining_size_credit);
+	struct mausb_host_ep	*ep = mausb_state_to_ep(ep_state);
+	struct mausb_urb	*maurb = container_of(tx_state,
+					struct mausb_urb, state);
+	struct mausb_hcd	*mhcd = mausb_host_ep_to_mahcd(ep);
+	unsigned long		irq_flags;
+
+	mausb_dbg(mhcd, "%s: received transferResponse with sequence number %i"
+		" for transfer %i\n", __func__, SN, tx_resp->data->req_id);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	/* look for sequence number and/or request ID errors */
+	if (should_drop_txResp(ep_state, tx_state, tx_resp, MAUSB_OUT)) {
+		mausb_drop_packet(ep, tx_resp);
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+		return payload_size;
+	}
+
+	switch (status) {
+	case SUCCESS:
+		/*  look for and acknowledge end of transfer */
+		if (ep_flags & MAUSB_PKT_TFLAG_EOT) {
+
+			spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+			host_send_ack(tx_state, MAUSB_OUT, ep_state,
+				 SUCCESS, SN);
+			spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+			ep_state->earliest_request_id =
+				mausb_req_id_add(
+					ep_state->earliest_request_id, 1);
+			ep_state->active_request_id =
+				mausb_req_id_add(
+					ep_state->active_request_id, 1);
+
+			tx_state->eot_detected = true;
+			tx_state->last_transfer_sn = SN;
+			maurb->urb->actual_length += tx_state->payload_size;
+		}
+
+		ep_state->earliest_unacked = SN + 1;
+		ep_state->rx_buf_size = credit - payload_size;
+		break;
+	case INVALID_REQUEST:
+		mausb_dbg(mhcd, "%s: status = INVALID_REQUEST\n", __func__);
+		/* TODO: start over with request number in packet */
+		break;
+	case DROPPED_PACKET:
+		mausb_dbg(mhcd, "%s: status = DROPPED_PACKET\n", __func__);
+		/* fallthrough, same as MISSING_SEQUENCE_NUMBER */
+	case MISSING_SEQUENCE_NUMBER:
+		mausb_dbg(mhcd, "%s: status = MISSING_SEQUENCE_NUMBER\n",
+		       __func__);
+		mausb_resend_multi_packets(ep, &ep->req_list,
+			le32_to_cpu(tx_resp->data->seq_num), irq_flags);
+		break;
+	case TRANSFER_PENDING:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_PENDING\n", __func__);
+		/* TODO: reset transmission counter */
+		break;
+	case TRANSFER_EP_STALL:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_EP_STALL\n", __func__);
+		if (ep_flags & MAUSB_PKT_TFLAG_EOT) {
+			spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+			host_send_ack(tx_state, MAUSB_OUT, ep_state,
+				      TRANSFER_EP_STALL, SN);
+			spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+			tx_state->eot_detected = true;
+		}
+		break;
+	case TRANSFER_CANCELLED:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_CANCELLED\n",
+			__func__);
+		break;
+	case TRANSFER_DATA_BUFFER_ERROR:
+		mausb_dbg(mhcd, "%s: status = TRANSFER_DATA_BUFFER_ERROR\n",
+		       __func__);
+		break;
+	default:
+		tx_state->transfer_error = true;
+		mausb_drop_packet(ep, tx_resp);
+		break;
+	}
+
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return payload_size;
+}
+
+
+/* --------------------- Transfer interfaces ----------------------*/
+
+/**
+ * Interface called to initiate an IN or OUT transfer.
+ *
+ * @ep:     Host endpoint associated with transfer.
+ * @maurb:  maurb with payload to transfer.
+ *	    NOTE: one maurb maps to one transfer.
+ * @dir_in: Transfer direction. Set to one if IN (to host) or zero if OUT.
+ *
+ * Only one transfer can be in progress at a time for a particular endpoint.
+ * When a transfer is in progress, the tx_pending flag for that endpoint is set
+ * indicating that the endpoint is busy.
+ */
+int start_ma_transfer(struct mausb_host_ep *ep, struct mausb_urb *maurb,
+		int dir_in)
+{
+	int				     tx_size;
+	unsigned long			     irq_flags;
+	char				     *tx_type;
+	struct mausb_hcd		     *mhcd = mausb_host_ep_to_mahcd(ep);
+	const struct usb_endpoint_descriptor *ep_desc;
+
+	ep_desc = mausb_get_ep_des(ep);
+
+	switch (usb_endpoint_type(ep_desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		tx_type = "control";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		tx_type = "isochronous";
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		tx_type = "bulk";
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		tx_type = "interrupt";
+		break;
+	default:
+		tx_type = "unknown";
+	}
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+
+	/* start a new transfer if there isn't one already in progress. */
+	if (ep->state.tx_pending == 0) {
+
+		ep->state.tx_pending = 1;
+		tx_size = maurb->urb->transfer_buffer_length;
+
+		/*
+		 * Set this transfer as active transfer for endpoint - this
+		 * is how we will get active transfer info when we receive
+		 * transferRequests.
+		 */
+		ep->active_transfer = maurb;
+
+		/* check to see if setup phase of control transfer */
+		if (mausb_control_xfer(maurb)) {
+			ep->state.seq_number = 0;
+			ep->state.earliest_unacked = 0;
+		}
+
+		spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+		/* initiate transfer by direction */
+		if (dir_in) {
+			mausb_dbg(mhcd, "%s: starting %s IN transfer for"
+				" endpoint %u\n", __func__, tx_type,
+				ep->ep_handle.ep_num);
+
+			host_init_IN_transfer(&maurb->state, ep, maurb);
+
+		} else {
+			mausb_dbg(mhcd, "%s: starting %s OUT transfer for"
+				" endpoint %u\n", __func__, tx_type,
+				ep->ep_handle.ep_num);
+
+			host_init_OUT_transfer(&maurb->state, ep, tx_size);
+			host_OUT_generate_txReqs(&maurb->state, &ep->state,
+				maurb);
+		}
+		spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return -EINPROGRESS;
+}
+
+/**
+ * Interface called to give a transferResp to the host for IN transfers.
+ *
+ * @pkt:      transferResponse packet being received.
+ * @context:  Host endpoint associated with transfer.
+ *
+ * After an IN transfer is initiated, the host waits to receive transferResponse
+ * packets from the device-side endpoint. When a transferResponse is received,
+ * the host updates its transfer and endpoint states and copies the packet
+ * payload into the maurb buffer associated with the tranfer. If the device
+ * requests a transferAck packet, one is sent.
+ */
+int complete_IN_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int				urb_stat;
+	int				length = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_urb		*maurb;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_hcd		*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	tx_resp = mausb_pkt_from_ms_pkt_ep(pkt, ep, GFP_ATOMIC);
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mhcd = mausb_host_ep_to_mahcd(ep);
+	maurb = ep->active_transfer;
+
+	if (NULL == maurb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EINVAL;
+	}
+
+	tx_state = &maurb->state;
+	length = host_IN_txResp_rcvd(&ep->state, tx_state, tx_resp);
+
+	/* something went wrong in receiving the transferResp packet */
+	if (length < 0) {
+		mausb_err(mhcd, "%s: returning error %i\n", __func__, length);
+		return length;
+	}
+
+	/* look for end of transfer */
+	if (tx_state->eot_detected) {
+		ep->state.tx_pending = 0;
+
+		urb_stat = mausb_to_urb_status(tx_resp->data->common.pkt_status);
+		if (NULL != maurb)
+			mausb_unlink_giveback_urb(maurb, urb_stat);
+	}
+
+	/* if not end of transfer, set timer between packets */
+	else {
+		mod_timer(&ep->timer,
+			jiffies + msecs_to_jiffies(MAUSB_TRANSFER_KEEP_ALIVE));
+	}
+
+	return length;
+}
+
+/**
+ * Interface called to give the host a transferResp packet.
+ *
+ * @pkt:     transferResponse packet being received.
+ * @context: Host endpoint associated with transfer.
+ *
+ * For OUT transfers the host sends a series of transferRequest packets. A
+ * transferResponse packet is only sent by the device when a transferAck packet
+ * is requested by the host or the end of the transfer is reached.
+ */
+int complete_OUT_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int				urb_stat;
+	int				ret = 0;
+	struct mausb_host_ep		*ep;
+	struct mausb_pkt		*tx_resp;
+	struct mausb_urb		*maurb;
+	struct mausb_transfer_state	*tx_state;
+	struct mausb_hcd		*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	tx_resp = mausb_pkt_from_ms_pkt_ep(pkt, ep, GFP_ATOMIC);
+	list_add_tail(&tx_resp->pkt_list, &ep->resp_list);
+
+	mhcd = mausb_host_ep_to_mahcd(ep);
+	maurb = ep->active_transfer;
+
+	if (NULL == maurb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EFAULT;
+	}
+
+	tx_state = &maurb->state;
+
+	/*
+	 * Look for Retry flag in packet and resend requested packets
+	 * if we have them. Otherwise, pass packet on to receiving process.
+	 */
+	if (mausb_is_a_retry(ep, &ep->req_list, tx_resp) == false)
+		ret = host_OUT_txResp_rcvd(&ep->state, tx_state, tx_resp);
+
+	/* make sure we still have an active transfer */
+	if (!ep->active_transfer) {
+		mausb_cleanup_ma_packets(ep,
+			le32_to_cpu(tx_resp->data->seq_num),
+			tx_resp->data->req_id);
+		mausb_unlink_giveback_urb(maurb, -EINVAL);
+		return ret;
+	}
+
+	/* handle end of transfer */
+	if (tx_state->eot_detected) {
+		ep->state.tx_pending = 0;
+		mausb_cleanup_ma_packets(ep,
+			le32_to_cpu(tx_resp->data->seq_num),
+			tx_resp->data->req_id);
+		urb_stat = mausb_to_urb_status(
+			tx_resp->data->common.pkt_status);
+		mausb_unlink_giveback_urb(maurb, urb_stat);
+	}
+
+	return ret;
+}
+
+/*
+ * Receives transferRequest packets for control endpoint (ep0).
+ *
+ * @pkt:     transferResponse packet being received.
+ * @context: Host endpoint associated with transfer. This should always be
+ *	     control endpoint (ep0).
+ *
+ * Control transfers can be either IN or OUT. Transfer direction is parsed
+ * from the urb associated with the transfer, then the appropriate completion
+ * function is called.
+ */
+int complete_control_transferRequest(struct ms_pkt *pkt, void *context)
+{
+	int			dir_in = 0;
+	struct mausb_host_ep	*ep;
+	struct mausb_hcd	*mhcd;
+
+	if ((NULL == context) || (NULL == pkt)) {
+		pr_err("%s: received NULL %s\n", __func__,
+			context ? "packet" : "context");
+		return -EFAULT;
+	}
+
+	ep = (struct mausb_host_ep *) context;
+	mhcd = mausb_host_ep_to_mahcd(ep);
+
+	if (NULL == mhcd) {
+		pr_err("%s: could not find MA USB HCD for endpoint"
+			" at 0x%p\n", __func__, ep);
+		return -EFAULT;
+	}
+
+	if (NULL == ep->active_transfer || NULL == ep->active_transfer->urb) {
+		mausb_err(mhcd, "%s: no active transfer for endpoint at %p\n",
+			__func__, ep);
+		return -EFAULT;
+	}
+
+	/* stop timeout timer */
+	del_timer(&ep->timer);
+
+	dir_in = usb_pipein(ep->active_transfer->urb->pipe);
+
+	if (dir_in)
+		complete_IN_transferRequest(pkt, context);
+	else
+		complete_OUT_transferRequest(pkt, context);
+
+	return 0;
+}
+
diff --git a/drivers/staging/mausb/drivers/mausb_tx.c b/drivers/staging/mausb/drivers/mausb_tx.c
new file mode 100644
index 0000000..02327a1
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx.c
@@ -0,0 +1,316 @@
+/* Name:        mausb_tx.c
+ * Description: Common functions for both host and device media agnostic
+ *              transfers.
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "mausb_pkt.h"
+#include "mausb_tx.h"
+#include "mausb_const.h"
+
+int mausb_transfer_data_pkt(struct mausb_pkt *pkt, struct mausb_host_ep *ep,
+		gfp_t mem_flags)
+{
+	int ret;
+
+	ret = mausb_pkt_fill_ms_pkt(pkt, mem_flags);
+	if (0 > ret)
+		return ret;
+
+	return mausb_transfer_packet(&pkt->pkt, &ep->tx_pair.to_ms);
+
+}
+EXPORT_SYMBOL(mausb_transfer_data_pkt);
+
+/**
+ * Opens an endpoint-specific connection between the media specific and media
+ * agnostic drivers in order to send and receive MA USB data packets.
+ *
+ * @drv:	  Media specific driver to establish connection with.
+ * @ep:  	  Host endpoint to be associated with this channel.
+ * @transfer_pkt: The call the MS driver should make when a packet is received.
+ */
+int mausb_add_data_channel(struct mausb_ms_drv *drv, struct mausb_host_ep *ep,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context))
+{
+	int				ret = 0;
+	struct mausb_transfer_pair	tx_pair;
+
+	matx_dbg("%s: adding channel for ep with handle %x\n", __func__,
+		ep->ep_handle.handle);
+
+	tx_pair.to_ma.transfer_packet = transfer_pkt;
+	tx_pair.to_ma.context = ep;
+	tx_pair.pkt_sent = NULL;
+	tx_pair.handle = ep->ep_handle.handle;
+
+	ret = drv->ops->add_transfer_pair(&tx_pair);
+
+	if (ret >= 0)
+		ep->tx_pair = tx_pair;
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_add_data_channel);
+
+/**
+ * Determines if conditions are met to complete a data transfer.
+ *
+ * @tx_state: State of transfer to be checked.
+ * @seq_num:  Sequence number to be compared to last sequence number in the
+ *	      transfer.
+ *
+ * Returns true if a transfer can be considered complete or false otherwise.
+ * Note that this does not differentiate between transfers that complete
+ * with and without an error.
+ */
+bool mausb_transfer_is_complete(struct mausb_transfer_state *tx_state,
+		u8 seq_num)
+{
+	bool complete = false;
+
+	if (!tx_state->transfer_error && tx_state->last_transfer_sn <= seq_num)
+		complete = true;
+
+	if (tx_state->transfer_error) {
+		matx_err("%s: transfer ending with error\n", __func__);
+		complete = true;
+	}
+
+	return complete;
+}
+EXPORT_SYMBOL(mausb_transfer_is_complete);
+
+/**
+ * Deletes packet from endpoint list and frees memory.
+ *
+ * @ep:	 Endpoint associated with packet to be dropped.
+ * @pkt: Packet to be dropped.
+ */
+void mausb_drop_packet(struct mausb_host_ep *ep, struct mausb_pkt *pkt)
+{
+	if (ep == NULL || pkt == NULL)
+		return;
+
+	list_del(&pkt->pkt_list);
+	mausb_free_pkt(pkt);
+
+	if (list_empty(&ep->req_list))
+		INIT_LIST_HEAD(&ep->req_list);
+
+	if (list_empty(&ep->resp_list))
+		INIT_LIST_HEAD(&ep->resp_list);
+}
+EXPORT_SYMBOL(mausb_drop_packet);
+
+/**
+ * Deletes all of the packets based on the sequence number.
+ *
+ * @ep:      Endpoint associated with transfer.
+ * @seq_num: The sequence number of the packets to delete. This will
+ *           delete all the packets with sequence numbers up to
+ *           (but not including) seq_num.
+ * @req_id:  The request ID of the packets to delete. This will
+ *           delete all the packets with request IDs up to
+ *           (but not including) req_id.
+ */
+void mausb_cleanup_ma_packets(struct mausb_host_ep *ep, u32 seq_num, u8 req_id)
+{
+	struct mausb_pkt *active, *next;
+
+	list_for_each_entry_safe(active, next, &ep->req_list, pkt_list) {
+		if (mausb_seq_num_lt(active->data->seq_num, seq_num) ||
+			mausb_req_id_lt(active->data->req_id, req_id))
+			mausb_drop_packet(ep, active);
+	}
+
+	list_for_each_entry_safe(active, next, &ep->resp_list, pkt_list) {
+		if (mausb_seq_num_lt(active->data->seq_num, seq_num) ||
+			mausb_req_id_lt(active->data->req_id, req_id))
+
+			mausb_drop_packet(ep, active);
+	}
+}
+EXPORT_SYMBOL(mausb_cleanup_ma_packets);
+
+/**
+ * Resend all packets starting from a given sequence number.
+ *
+ * @ep:		Endpoint associated with packets.
+ * @pkt_list: 	Head of list of packets to search.
+ * @seq_num: 	Sequence number of first packet to be sent.
+ *
+ * Returns 0 if at least one packet is sent, otherwise returns non-zero value.
+ * Note: the caller should be holding the endpoint's spinlock.
+ */
+int mausb_resend_multi_packets(struct mausb_host_ep *ep,
+		struct list_head *pkt_list,
+		u32 seq_num, unsigned long irq_flags)
+{
+	int			ret = -EINVAL;
+	struct mausb_pkt	*pkt;
+	int			i = 0;
+
+	list_for_each_entry(pkt, pkt_list, pkt_list) {
+
+		i++;
+		if (mausb_seq_num_gt_eq(pkt->data->seq_num, seq_num)) {
+			matx_dbg("%s: resending pkt %i\n", __func__,
+				pkt->data->seq_num);
+			pkt->common->ver_flags |= MAUSB_PKT_FLAG_RETRY;
+			ret = 0;
+			mausb_transfer_data_pkt(pkt, ep, GFP_ATOMIC);
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(mausb_resend_multi_packets);
+
+/**
+ * Checks to see if a received packet is a retry and resends response packets
+ * (if found).
+ *
+ * @ep:		Endpoint associated with transfer.
+ * @pkt_list:	List of packets previously sent.
+ * @pkt:	Received packet.
+ *
+ * Returns true if received packet has the Retry flag set AND at least one
+ * response packet was found and sent. Returns false if the Retry flag not
+ * set or the Retry flag is set but no corresponding packets have been found.
+ */
+bool mausb_is_a_retry(struct mausb_host_ep *ep, struct list_head *pkt_list,
+		struct mausb_pkt *pkt)
+{
+	int			err	= 0;
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	if (pkt->common->ver_flags & MAUSB_PKT_FLAG_RETRY) {
+		matx_dbg("%s: packet is a retry\n", __func__);
+
+		/*
+		 * If received packet is a retry, look to see if we've
+		 * already generated the corresponding packets.
+		 */
+		err = mausb_resend_multi_packets(ep, pkt_list,
+			pkt->data->seq_num,
+				irq_flags);
+
+		/*
+		 * Only return true if packet is found, otherwise we might
+		 * miss responding to a packet we never received.
+		 */
+		if (err == 0)
+			return true;
+	}
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+
+	return false;
+}
+EXPORT_SYMBOL(mausb_is_a_retry);
+
+/**
+ * Called by timeout timer to start thread that handles error handling and
+ * packet resends.
+ *
+ * Used to avoid passing packets to a medium while in an interrupt context,
+ * which can be problematic for some mediums.
+ */
+void wake_timeout_thread(unsigned long _ep)
+{
+	struct mausb_host_ep	*ep = (struct mausb_host_ep *) _ep;
+	unsigned long		irq_flags;
+
+	matx_dbg("%s: timeout occurred!!!\n", __func__);
+
+	spin_lock_irqsave(&ep->ep_lock, irq_flags);
+	ep->tx_timed_out = true;
+	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
+	wake_up_interruptible(&ep->host_ep_wq);
+}
+
+/**
+ * Fills packet fields based on the given EP. Also fills device fields.
+ */
+void mausb_fill_pkt_ep(struct mausb_pkt *pkt, struct mausb_host_ep *ma_ep)
+{
+	struct mausb_dev	*mausb_dev;
+	struct ma_dev		*ma_dev;
+	unsigned long		irq_flags;
+
+	spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
+
+	if (MAUSB_EP_HANDLE_ACTIVE != ma_ep->ep_handle_state) {
+		matx_warn("%s: endpoint handle not active\n", __func__);
+	}
+
+	pkt->common->ep_handle = ma_ep->ep_handle;
+	pkt->data->eps_tflags |= ma_ep->ep_handle_state;
+	/* TODO: set transfer Type */
+
+	mausb_dev = ma_ep->mausb_dev;
+	spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
+
+
+	spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
+	ma_dev = mausb_dev->ma_dev;
+	spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
+
+
+	spin_lock_irqsave(&ma_dev->ma_dev_lock, irq_flags);
+	pkt->common->ma_dev_addr = ma_dev->ma_dev_addr;
+	pkt->common->mass_id = ma_dev->mass_id;
+	spin_unlock_irqrestore(&ma_dev->ma_dev_lock, irq_flags);
+}
+EXPORT_SYMBOL(mausb_fill_pkt_ep);
diff --git a/drivers/staging/mausb/drivers/mausb_tx.h b/drivers/staging/mausb/drivers/mausb_tx.h
new file mode 100644
index 0000000..c68ac09
--- /dev/null
+++ b/drivers/staging/mausb/drivers/mausb_tx.h
@@ -0,0 +1,127 @@
+/* Name:        mausb_tx.h
+ * Description:	header file for mausb_tx-device.c and mausb_tx-host.c
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information:
+ * Sean Stalley, sean.stalley@intel.com
+ * Stephanie Wallick, stephanie.s.wallick@intel.com
+ * 2111 NE 25th Avenue
+ * Hillsboro, Oregon 97124
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+   * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MAUSB_TX_H
+#define __MAUSB_TX_H
+
+#include "mausb_mem.h"
+#include "mausb_pkt.h"
+
+#ifdef DEBUG
+#define matx_dbg(format, arg...) \
+	printk(KERN_DEBUG format, ##arg)
+#else
+#define matx_dbg(format, arg...)
+#endif
+
+#define matx_warn(format, arg...) \
+	printk(KERN_WARNING format, ##arg)
+
+#define matx_err(format, arg...) \
+	printk(KERN_ERR format, ##arg)
+
+/* TODO: for now this is set to match gadget zero's buffer size, but
+ * eventually we need to get this value from the device instead of
+ * predefining it. */
+# define DEVICE_RX_BUF_SIZE 4096
+
+#define MAUSB_WAIT_GADGET_BUFFER_FREE_TIMEOUT 3000
+
+/* functions common to both host and device */
+int mausb_add_data_channel(struct mausb_ms_drv *drv, struct mausb_host_ep *ep,
+		int (*transfer_pkt)(struct ms_pkt *pkt, void *context));
+
+int mausb_transfer_data_pkt(struct mausb_pkt *pkt, struct mausb_host_ep *ep,
+		gfp_t mem_flags);
+bool mausb_transfer_is_complete(struct mausb_transfer_state *tx_state,
+		u8 seq_num);
+void mausb_drop_packet(struct mausb_host_ep *ep, struct mausb_pkt *pkt);
+void mausb_cleanup_ma_packets(struct mausb_host_ep *ep, u32 seq_num,
+		u8 req_id);
+bool mausb_is_a_retry(struct mausb_host_ep *ep, struct list_head *pkt_list,
+		struct mausb_pkt *pkt);
+int mausb_resend_multi_packets(struct mausb_host_ep *ep,
+		struct list_head *pkt_list, u32 seq_num,
+		unsigned long irq_flags);
+void mausb_fill_pkt_ep(struct mausb_pkt *pkt, struct mausb_host_ep *ma_ep);
+
+/* transfer interface function declarations */
+int complete_control_transferRequest(struct ms_pkt *pkt, void *context);
+int complete_IN_transferRequest(struct ms_pkt *pkt, void *context);
+int complete_OUT_transferRequest(struct ms_pkt *pkt, void *context);
+int receive_ma_packet_control(struct ms_pkt *ms_pkt, void *context);
+int receive_ma_packet_IN(struct ms_pkt *ms_pkt, void *context);
+int receive_ma_packet_OUT(struct ms_pkt *ms_pkt, void *context);
+int start_ma_transfer(struct mausb_host_ep *ep, struct mausb_urb *maurb,
+		int dir_in);
+
+/* transfer state fucntion declarations */
+int device_OUT_deliver_payload(struct mausb_pkt *tx_req,
+		struct mausb_ep_state *ep_state,
+		struct mausb_transfer_state *tx_state);
+int device_OUT_send_txResp(struct mausb_transfer_state *tx_state,
+		struct mausb_ep_state *ep_state, u32 req_id,
+		u32 seq_num, int status, bool retry, bool eot, bool arq);
+void host_IN_txReq_transmit(struct mausb_pkt *tx_req, struct mausb_host_ep *ep,
+		struct mausb_transfer_state *tx_state);
+int device_IN_send_null_txResp(struct mausb_host_ep *ep, u8 req_id, int status);
+
+/* transfer timeout function declarations */
+void wake_timeout_thread(unsigned long _ep);
+int host_transfer_timeout(void *data);
+int device_transfer_timeout(void *data);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (6 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  2:09   ` [V2 PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

Adds various scripts for building, loading and unloading the MA USB
drivers and a utility that can be used for connecting and disconnecting
the host and device drivers.

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 drivers/staging/mausb/mausb-util/AUTHORS           |   2 +
 drivers/staging/mausb/mausb-util/Android.mk        |   3 +
 drivers/staging/mausb/mausb-util/ChangeLog         |   0
 drivers/staging/mausb/mausb-util/INSTALL           |   0
 drivers/staging/mausb/mausb-util/LICENCE           |   0
 drivers/staging/mausb/mausb-util/Makefile          |  14 ++
 drivers/staging/mausb/mausb-util/README            |  68 +++++++
 drivers/staging/mausb/mausb-util/config.mk         |  17 ++
 drivers/staging/mausb/mausb-util/src/Android.mk    |  13 ++
 drivers/staging/mausb/mausb-util/src/Makefile      |  18 ++
 drivers/staging/mausb/mausb-util/src/connect.c     |  69 +++++++
 drivers/staging/mausb/mausb-util/src/connect.h     |  22 +++
 drivers/staging/mausb/mausb-util/src/mausb.c       | 201 +++++++++++++++++++++
 drivers/staging/mausb/mausb-util/src/mausb.h       |  64 +++++++
 drivers/staging/mausb/mausb-util/src/mausb_ioctl.h |  24 +++
 drivers/staging/mausb/mausb-util/src/utils.c       |  94 ++++++++++
 drivers/staging/mausb/scripts/Android.mk           |  38 ++++
 .../staging/mausb/scripts/build_load_connect.sh    |  69 +++++++
 drivers/staging/mausb/scripts/load_gzero.sh        |   5 +
 .../mausb/scripts/load_mausb_android-dev.sh        |  31 ++++
 .../mausb/scripts/load_mausb_android-host.sh       |  31 ++++
 .../staging/mausb/scripts/load_mausb_android.sh    |  33 ++++
 drivers/staging/mausb/scripts/load_script.sh       | 125 +++++++++++++
 drivers/staging/mausb/scripts/modprobify.sh        |  10 +
 drivers/staging/mausb/scripts/unload_gzero.sh      |   5 +
 25 files changed, 956 insertions(+)
 create mode 100644 drivers/staging/mausb/mausb-util/AUTHORS
 create mode 100644 drivers/staging/mausb/mausb-util/Android.mk
 create mode 100644 drivers/staging/mausb/mausb-util/ChangeLog
 create mode 100644 drivers/staging/mausb/mausb-util/INSTALL
 create mode 100644 drivers/staging/mausb/mausb-util/LICENCE
 create mode 100644 drivers/staging/mausb/mausb-util/Makefile
 create mode 100644 drivers/staging/mausb/mausb-util/README
 create mode 100644 drivers/staging/mausb/mausb-util/config.mk
 create mode 100644 drivers/staging/mausb/mausb-util/src/Android.mk
 create mode 100644 drivers/staging/mausb/mausb-util/src/Makefile
 create mode 100644 drivers/staging/mausb/mausb-util/src/connect.c
 create mode 100644 drivers/staging/mausb/mausb-util/src/connect.h
 create mode 100644 drivers/staging/mausb/mausb-util/src/mausb.c
 create mode 100644 drivers/staging/mausb/mausb-util/src/mausb.h
 create mode 100644 drivers/staging/mausb/mausb-util/src/mausb_ioctl.h
 create mode 100644 drivers/staging/mausb/mausb-util/src/utils.c
 create mode 100644 drivers/staging/mausb/scripts/Android.mk
 create mode 100755 drivers/staging/mausb/scripts/build_load_connect.sh
 create mode 100755 drivers/staging/mausb/scripts/load_gzero.sh
 create mode 100755 drivers/staging/mausb/scripts/load_mausb_android-dev.sh
 create mode 100755 drivers/staging/mausb/scripts/load_mausb_android-host.sh
 create mode 100755 drivers/staging/mausb/scripts/load_mausb_android.sh
 create mode 100755 drivers/staging/mausb/scripts/load_script.sh
 create mode 100755 drivers/staging/mausb/scripts/modprobify.sh
 create mode 100755 drivers/staging/mausb/scripts/unload_gzero.sh

diff --git a/drivers/staging/mausb/mausb-util/AUTHORS b/drivers/staging/mausb/mausb-util/AUTHORS
new file mode 100644
index 0000000..6312e6a
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/AUTHORS
@@ -0,0 +1,2 @@
+Sean O. Stalley <sean.stalley@intel.com>
+Aymen Zayet <aymen.zayet@intel.com>
diff --git a/drivers/staging/mausb/mausb-util/Android.mk b/drivers/staging/mausb/mausb-util/Android.mk
new file mode 100644
index 0000000..c455f97
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/drivers/staging/mausb/mausb-util/ChangeLog b/drivers/staging/mausb/mausb-util/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/drivers/staging/mausb/mausb-util/INSTALL b/drivers/staging/mausb/mausb-util/INSTALL
new file mode 100644
index 0000000..e69de29
diff --git a/drivers/staging/mausb/mausb-util/LICENCE b/drivers/staging/mausb/mausb-util/LICENCE
new file mode 100644
index 0000000..e69de29
diff --git a/drivers/staging/mausb/mausb-util/Makefile b/drivers/staging/mausb/mausb-util/Makefile
new file mode 100644
index 0000000..abd5fe0
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/Makefile
@@ -0,0 +1,14 @@
+include config.mk
+
+.PHONY: $(BINARY_NAME) all clean
+
+all: $(BINARY_NAME)
+
+$(BINARY_NAME):
+	$(MAKE) -C src/
+	cp -rf src/$(BINARY_NAME) .
+
+
+clean:
+	$(MAKE) -C src/ clean
+	rm -rf $(BINARY_NAME) *~
diff --git a/drivers/staging/mausb/mausb-util/README b/drivers/staging/mausb/mausb-util/README
new file mode 100644
index 0000000..c921355
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/README
@@ -0,0 +1,68 @@
+#    #   ##   #    #  ####  #####     #    # ##### # #      # ##### #   #
+##  ##  #  #  #    # #      #    #    #    #   #   # #      #   #    # #
+# ## # #    # #    #  ####  #####     #    #   #   # #      #   #     #
+#    # ###### #    #      # #    #    #    #   #   # #      #   #     #
+#    # #    # #    # #    # #    #    #    #   #   # #      #   #     #
+#    # #    #  ####   ####  #####      ####    #   # ###### #   #     #
+
+
+Author: Aymen Zayet
+License: GPL2
+Version: 0.1
+
+1. Description
+--------------
+This tool includes many commands that help to test / debug the MAUSB devices.
+mausb bin provides to the host a way to connect and disconnect from the MAUSB device
+by selecting the mode (ip or llc).
+
+2. Usage
+--------
+(*) The following steps can be used to test the connection between two Moorefield based devices :
+
+>> adb devices
+List of devices attached
+INV140200379	device
+INV140200169	device
+
+for device INV140200379:
+>>adb -s INV140200379 shell busybox ifconfig wlan0
+wlan0     Link encap:Ethernet  HWaddr 78:FF:57:00:6D:7A
+          inet addr:192.168.2.100  Bcast:192.168.2.255  Mask:255.255.255.0
+          inet6 addr: fe80::7aff:57ff:fe00:6d7a/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:264 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:287 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000
+          RX bytes:29906 (29.2 KiB)  TX bytes:29267 (28.5 KiB)
+
+for device INV140200169:
+>> adb -s INV140200169 shell busybox ifconfig wlan0
+wlan0     Link encap:Ethernet  HWaddr 78:FF:57:00:6C:A8
+          inet addr:192.168.2.113  Bcast:192.168.2.255  Mask:255.255.255.0
+          inet6 addr: fe80::7aff:57ff:fe00:6ca8/64 Scope:Link
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:268 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:290 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000
+          RX bytes:31168 (30.4 KiB)  TX bytes:30413 (29.7 KiB)
+
+run INV140200379 as a MAUSB host:
+>> adb -s INV140200379 shell load_mausb_android-host.sh
+mausb load process complete
+
+then run INV140200169 as MAUSB device:
+>>adb -s INV140200169 shell load_mausb_android-dev.sh
+mausb load process complete
+
+now on the device side , run :
+>> mausb --mode llc --connect --addr 78:FF:57:00:6D:7A
+
+then from the host side, run :
+>> mausb --mode llc --connect --addr 78:FF:57:00:6C:A8 
+
+3. Documentation
+----------------
+
+4. Miscellaneous
+----------------
diff --git a/drivers/staging/mausb/mausb-util/config.mk b/drivers/staging/mausb/mausb-util/config.mk
new file mode 100644
index 0000000..d272823
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/config.mk
@@ -0,0 +1,17 @@
+SRCDIR          = $(shell pwd)
+DESTDIR         = /usr/local/bin
+
+CC              = gcc
+CFLAGS          = -g -ggdb -D __DEBUG
+LDFLAGS         =
+SHELL           = /bin/sh
+#CFLAGS         = -O2 -fomit-frame-pointer                                                 
+
+PROJECT_NAME    = mausb
+PROJECT_VERSION = 0.1
+
+BINARY_NAME     = $(PROJECT_NAME)
+
+SOURCE_FILES    = utils.c connect.c mausb.c
+
+OBJECT_FILES    = $(SOURCE_FILES:.c=.o)
diff --git a/drivers/staging/mausb/mausb-util/src/Android.mk b/drivers/staging/mausb/mausb-util/src/Android.mk
new file mode 100644
index 0000000..881c5fc
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -Wall -g
+LOCAL_LDFLAGS +=
+LOCAL_LDLIBS += -lpthread -lm -ldl
+LOCAL_SRC_FILES:= \
+	mausb.c \
+	utils.c \
+	connect.c
+LOCAL_C_INCLUDES += linux/modules/ma-usb/drivers
+LOCAL_MODULE := mausb
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
diff --git a/drivers/staging/mausb/mausb-util/src/Makefile b/drivers/staging/mausb/mausb-util/src/Makefile
new file mode 100644
index 0000000..deb98a6
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/Makefile
@@ -0,0 +1,18 @@
+include ../config.mk
+
+all: $(BINARY_NAME)
+
+$(BINARY_NAME): $(OBJECT_FILES)
+	@echo -n "(LD)" $@ " "
+	@$(CC) $(LDFLAGS) $(CFLAGS) $^ -o $@
+	@echo OK
+
+%.o: %.c
+	@echo -n "(CC)" $@ " "
+	@$(CC) $(CFLAGS) -c $< -o $@
+	@echo OK
+
+clean:
+	rm -rf *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c .tmp_versions Module*.symv\
+ers
+	rm -f $(BINARY_NAME) *~
\ No newline at end of file
diff --git a/drivers/staging/mausb/mausb-util/src/connect.c b/drivers/staging/mausb/mausb-util/src/connect.c
new file mode 100644
index 0000000..6d6936b
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/connect.c
@@ -0,0 +1,69 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "mausb.h"
+
+int set_ipv4_addr(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: setting ip address\n", __func__);
+	sprintf(buf, "%u", config->ip);
+	if (0 <= ioctl(config->device, IOCTL_SET_IP, buf))
+		return 0;
+	return errno;
+}
+
+int set_mac_addr(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: setting mac address\n", __func__);
+	memcpy(buf, config->mac, 6);
+	if (0 <= ioctl(config->device, IOCTL_SET_MAC, buf)) {
+		printf("Msg from kernel space : mac %s set successfully\n",
+		       (char *)buf);
+		return 0;
+	}
+	return errno;
+}
+int set_port(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: setting port\n", __func__);
+	sprintf(buf, "%u", config->port);
+	if (0 <= ioctl(config->device, IOCTL_SET_PORT, buf))
+		return 0;
+	return errno;
+}
+
+int connect_device(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: connecting device\n", __func__);
+	if (0 <= ioctl(config->device, IOCTL_GADGET_C, buf))
+		return 0;
+	return errno;
+}
+
+int disconnect_device(mausb_t *config)
+{
+	char buf[128] = {0};
+	printf("%s: disconnecting device\n", __func__);
+	if (0 <= ioctl(config->device, IOCTL_GADGET_D, buf))
+		return 0;
+	return errno;
+}
diff --git a/drivers/staging/mausb/mausb-util/src/connect.h b/drivers/staging/mausb/mausb-util/src/connect.h
new file mode 100644
index 0000000..30bd1c5
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/connect.h
@@ -0,0 +1,22 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CONNECT_H_
+#define CONNECT_H_
+
+#endif /* CONNECT_H_ */
diff --git a/drivers/staging/mausb/mausb-util/src/mausb.c b/drivers/staging/mausb/mausb-util/src/mausb.c
new file mode 100644
index 0000000..67903a6
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/mausb.c
@@ -0,0 +1,201 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mausb.h"
+
+
+
+static struct option l_opts[] = {
+	/* no_argument options */
+	{"help", no_argument, 0, 'h'},
+	{"verbose", no_argument, 0, 'v'},
+	{"connect", no_argument, 0, 'c'},
+	{"disconnect", no_argument, 0, 'd'},
+
+	/* required_argument options */
+	{"addr", required_argument, 0, 'a'},
+	{"port", required_argument, 0, 'p'},
+	{"mode", required_argument, 0, 'm'},
+
+	/* end */
+	{0, 0, 0, 0},
+};
+
+static void usage(const char *this)
+{
+	fprintf(stderr,
+		"Usage: "
+		"\t%s [[options]] command"
+		"\n\t\t [--help/-h] show this help"
+		"\n\t\t [--verbose/-h] Add more trace about what's going on"
+		"\n\t\t [--mode/-m] mausb mode to be used : ip (default) or llc"
+		"\n\t\t [--connect/-c] connect to mausb device"
+		"\n\t\t [--disconnect/-d] disconnect from mausb device"
+		"\n\t\t [--port/-p] set the port number in case of tcp connection"
+		"\n\t\t [--addr/-a] ip or mac address depending on the given mode"
+		"\n", this);
+	return ;
+}
+
+static int check_config(void)
+{
+	int ret;
+
+	if (config.cmd == disconnect)
+		return 0;
+
+	switch (config.mode) {
+	case ip:
+		ret = !config.port;
+		break;
+	case llc:
+		ret = !config.mac;
+		break;
+	default:
+		ret = !! config.mode;
+	}
+
+	return ((config.cmd > max_command) ||
+		(config.mode > supported_mode) ||
+		ret);
+}
+
+static void print_config(void)
+{
+	return ;
+}
+
+static int process_options(int argc, char **argv)
+{
+	int option;
+
+	memset(&config, 0, sizeof(mausb_t));
+        config.mode = ip;
+	while ((option = getopt_long(argc, argv, "hfp:a:cdvm:", l_opts, NULL)) != EOF) {
+		switch(option) {
+		case 'h': // help
+			usage(argv[0]);
+			exit(0);
+			break;
+
+		case 'v': // verbose
+			config.verbose = 1;
+			break;
+ 
+		case 'c': // connect
+			config.cmd = connect;
+			break;
+
+		case 'd': // disconnect
+			config.cmd = disconnect;
+			break;
+
+		case 'm': // mode
+			if (strlen(optarg) == 3 && !strncmp(optarg, "llc", 3))
+				config.mode = llc;
+			else if (strlen(optarg) == 2 && !strncmp(optarg, "ip", 2))
+				config.mode = ip;
+			else {
+				fprintf(stderr, "could not determine mode\n");
+				goto err_options;
+			}
+			break;
+
+		case 'a': // addr
+			if (config.mode == llc) {
+				if (MACADDR_STR_SIZE != strlen(optarg))
+					goto err_options;
+				if (get_mac_address(optarg, config.mac))
+					goto err_options;
+			} else {
+				if (strlen(optarg) >= IPADDR_MAX)
+					goto err_options;
+				if (convert_ipv4_to_uint32(optarg, &config.ip))
+					goto err_options;
+				strcpy(config.ip_addr, optarg);
+			}
+			break;
+
+		case 'p': // port
+			config.port = atoi(optarg);
+			break;
+
+		default:
+			fprintf(stderr, "invalid option %c\n", option);
+			goto err_options;
+			break;
+		}
+	}
+
+	if (check_config()) {
+		fprintf(stderr, "check_config() failed\n");
+		goto err_options;
+	}
+
+	if (config.verbose)
+		print_config();
+
+	return 0;
+
+err_options:
+	usage(argv[0]);
+	return -1;
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	if (ret = process_options(argc, argv))
+		goto error;
+
+	printf("progran terminated successfully ip %x %s %d\n", config.ip,
+	       config.ip_addr, config.port);
+
+	ret = config.device = open(MAUSB_DEVICE, 0);
+	if (ret < 0) {
+		fprintf(stderr, "cannot open device %d\n", ret);
+		goto error;
+	}
+
+	switch(config.cmd) {
+	case connect:
+		if (config.verbose)
+			printf("connecting to %s port %u\n", config.ip_addr, config.port);
+		if (config.mode == llc) {
+			if (ret = set_mac_addr(&config))
+				goto close_device;
+		} else {
+			if (ret = set_ipv4_addr(&config))
+				goto close_device;
+			if (ret = set_port(&config))
+				goto close_device;
+		}
+		if  (ret = connect_device(&config))
+			goto close_device;
+		break;
+	case disconnect:
+		disconnect_device(&config);
+		break;
+	}
+close_device:
+	close(config.device);
+error:
+	return ret;
+}
diff --git a/drivers/staging/mausb/mausb-util/src/mausb.h b/drivers/staging/mausb/mausb-util/src/mausb.h
new file mode 100644
index 0000000..547bc92a
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/mausb.h
@@ -0,0 +1,64 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef MAUSB_H_
+#define MAUSB_H_
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include "connect.h"
+#include "mausb_ioctl.h"
+
+#define MAUSB_DEVICE "/dev/mausb"
+#define IPADDR_MAX 16
+#define MACADDR_STR_SIZE 17 /* excluding null termination char */
+
+typedef enum {
+	connect,
+	disconnect,
+	max_command,
+} mausb_cmd;
+
+typedef enum {
+	ip,
+	llc,
+	supported_mode,
+} mausb_mode;
+
+typedef struct {
+	int device;		       // file descriptor of the mausb device
+	char verbose;		       // is verbose mode enabled
+	mausb_cmd cmd;		       // keep the requested command to execute
+	uint32_t ip;		       // ip address of the device in case of ip mode
+	char ip_addr[IPADDR_MAX];      // ip address given in cmdline (x.x.x.x)
+	uint8_t mac[6];		       // mac address (aa:bb:cc:dd:ee:ff)
+	uint32_t port;		       // ip port number in case of ip mode
+	mausb_mode mode;	       // default is ip
+} mausb_t;
+
+mausb_t config;
+int convert_ipv4_to_uint32(char *, uint32_t *);
+
+int get_mac_address(char *, uint8_t *);
+#endif /* MAUSB_H_ */
diff --git a/drivers/staging/mausb/mausb-util/src/mausb_ioctl.h b/drivers/staging/mausb/mausb-util/src/mausb_ioctl.h
new file mode 100644
index 0000000..e6953d3
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/mausb_ioctl.h
@@ -0,0 +1,24 @@
+#ifndef MAUSB_IOCTL_H
+#define MAUSB_IOCTL_H
+
+#define BUFFER 80
+#define DRIVER_VERSION "Alpha 0.0.25"
+#define MAJOR_NUM 100
+
+/* These define the ioctl functions that can be used */
+#define IOCTL_GET_VRSN _IOR(MAJOR_NUM, 0, char *)
+#define IOCTL_GET_NAME _IOR(MAJOR_NUM, 1, char *)
+#define IOCTL_GADGET_C _IOR(MAJOR_NUM, 2, char *)
+#define IOCTL_GADGET_D _IOR(MAJOR_NUM, 3, char *)
+#define IOCTL_SET_IP   _IOR(MAJOR_NUM, 4, char *)
+#define IOCTL_SET_PORT _IOR(MAJOR_NUM, 5, char *)
+#define IOCTL_SET_MAC  _IOR(MAJOR_NUM, 6, char *)
+
+
+/* This is the location where the device file will be created. It is used to
+ * read/write to in order to communicate to and from the device */
+#define DEVICE_FILE_NAME "/dev/mausb"
+
+#define ETH_ALEN 6
+
+#endif
diff --git a/drivers/staging/mausb/mausb-util/src/utils.c b/drivers/staging/mausb/mausb-util/src/utils.c
new file mode 100644
index 0000000..f06e2ce
--- /dev/null
+++ b/drivers/staging/mausb/mausb-util/src/utils.c
@@ -0,0 +1,94 @@
+/*
+  (c) Aymen Zayet (aymen.zayet@intel.com)
+
+  This file is part of mausb utility.
+
+  mausb is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 2 of the License, or
+  (at your option) any later version.
+
+  mausb is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with mausb. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "mausb.h"
+
+int convert_ipv4_to_uint32(char *addr, uint32_t *ipnum)
+{
+	uint8_t digits[4];
+	int i, j = 0;
+        char ip[64];
+
+	if (addr == NULL)
+		goto input_err;
+
+	strncpy(ip, addr, strlen(addr)+1);
+	i = strlen(ip);
+	memset(digits, 0, 4);
+
+	if (IPADDR_MAX < strlen(ip))
+		goto input_err;
+
+again:
+	while (i-1 && ip[--i - 1] != '.');
+        if (i-1) {
+                ip[i-1] = '\0';
+                digits[j++] = atoi(ip+i);
+		goto again;
+        } else
+                digits[j++] = atoi(ip);
+
+	*ipnum = digits[3] << 24 |
+		digits[2] << 16 |
+		digits[1] << 8 |
+		digits[0] << 0;
+
+        return 0;
+
+input_err:
+	return -1;
+}
+
+
+int get_mac_address(char *addr, uint8_t *out)
+{
+
+	uint8_t digits[6];
+	int i, j = 0;
+	char mac[64];
+
+	if (addr == NULL)
+		goto input_err;
+
+	strncpy(mac, addr, strlen(addr)+1);
+	i = strlen(mac);
+	memset(digits, 0, 6);
+
+	if (MACADDR_STR_SIZE != strlen(mac))
+		goto input_err;
+
+again:
+	while (i-1 && mac[--i - 1] != ':');
+	if (i-1) {
+		mac[i-1] = '\0';
+		digits[j++] = strtol(mac+i, NULL, 16);
+		goto again;
+	} else
+		digits[j++] = strtol(mac, NULL, 16);
+
+	for (i = 0; i < 6; i++) {
+                printf("[%d]=0x%x ", i, digits[i]);
+		out[5-i] = digits[i];
+        }
+
+        printf("\n");
+	return 0;
+
+input_err:
+	return -1;
+}
diff --git a/drivers/staging/mausb/scripts/Android.mk b/drivers/staging/mausb/scripts/Android.mk
new file mode 100644
index 0000000..ddba51a
--- /dev/null
+++ b/drivers/staging/mausb/scripts/Android.mk
@@ -0,0 +1,38 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := load_mausb_android.sh
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := EXECUTABLE
+
+ifeq ($(TARGET_OUT_EXECUTABLE),)
+TARGET_OUT_EXECUTABLE := $(TARGET_OUT)/bin
+endif
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := load_mausb_android-host.sh
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := EXECUTABLE
+
+ifeq ($(TARGET_OUT_EXECUTABLE),)
+TARGET_OUT_EXECUTABLE := $(TARGET_OUT)/bin
+endif
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := load_mausb_android-dev.sh
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := EXECUTABLE
+
+ifeq ($(TARGET_OUT_EXECUTABLE),)
+TARGET_OUT_EXECUTABLE := $(TARGET_OUT)/bin
+endif
+
+include $(BUILD_PREBUILT)
\ No newline at end of file
diff --git a/drivers/staging/mausb/scripts/build_load_connect.sh b/drivers/staging/mausb/scripts/build_load_connect.sh
new file mode 100755
index 0000000..f40cdd7
--- /dev/null
+++ b/drivers/staging/mausb/scripts/build_load_connect.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+side="invalid"
+mode="invalid"
+addr="invalid"
+
+while getopts "hdbtsa:" opt; do
+	case "$opt" in
+	h) side="-h"
+	   ;;
+	d) side="-d"
+	   ;;
+	b) side="-b"
+	   ;;
+	t) mode="-t"
+	   ;;
+	s) mode="-s"
+	   ;;
+	a) addr=$OPTARG
+	   ;;
+	esac
+done
+
+
+if [ "$side" == "invalid" ]
+then
+	echo $side
+	echo "please choose host (-h) or device (-d)"
+	exit
+fi
+
+if [ "$mode" == "invalid" ]
+then
+	echo $mode
+	echo "please choose tcp (-t) or snap (-s)"
+	exit
+fi
+
+if [ "$addr" == "invalid" ]
+then
+	echo $addr
+	echo "please enter a valid address (-a 1.2.3.4, -a 01:23:45:67:89:0a)"
+	exit
+fi
+
+
+cd ../
+# make clean && make
+make -j8
+cd drivers/
+
+wireshark -k -i eth0 &
+
+sudo ../scripts/load_script.sh $side $mode
+
+sudo cat /proc/modules | grep ma
+
+if [ "$mode" == "-s" ]
+then
+	echo "connecting mausb"
+	../tools/mausb-util/mausb -c -m llc -a $addr
+fi
+
+if [ "$mode" == "-t" ]
+then
+	echo "connecting mausb"
+	../tools/mausb-util/mausb -c -m ip -p 9001 -a $addr
+fi
+
diff --git a/drivers/staging/mausb/scripts/load_gzero.sh b/drivers/staging/mausb/scripts/load_gzero.sh
new file mode 100755
index 0000000..9266199
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_gzero.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+modprobe g_zero
+
+echo g_zero load process complete
\ No newline at end of file
diff --git a/drivers/staging/mausb/scripts/load_mausb_android-dev.sh b/drivers/staging/mausb/scripts/load_mausb_android-dev.sh
new file mode 100755
index 0000000..c23cdef
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_mausb_android-dev.sh
@@ -0,0 +1,31 @@
+#!/system/xbin/ash
+
+# For Android targets, insmod shall be used since
+# the ueventd take care of the dependencies.
+
+GREEN="\\033[1;32m"
+NORMAL="\\033[0;39m"
+RED="\\033[1;31m"
+
+load_module()
+{
+    insmod $1
+    if [ $? -ne 0 ]; then
+	echo -e $RED
+	echo "unable to insmod $1 (err : $?)"
+	echo -e $NORMAL
+	exit $?
+    fi
+}
+
+
+load_module /lib/modules/matcp_core.ko
+load_module /lib/modules/maudc.ko
+#load_module /lib/modules/mamed.ko
+load_module /lib/modules/matcp_dev.ko
+
+mknod /dev/mausb c 100 0
+
+echo -e $GREEN
+echo "mausb load process complete"
+echo -e $NORMAL
diff --git a/drivers/staging/mausb/scripts/load_mausb_android-host.sh b/drivers/staging/mausb/scripts/load_mausb_android-host.sh
new file mode 100755
index 0000000..85f0a20
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_mausb_android-host.sh
@@ -0,0 +1,31 @@
+#!/system/xbin/ash
+
+# For Android targets, insmod shall be used since
+# the ueventd take care of the dependencies.
+
+GREEN="\\033[1;32m"
+NORMAL="\\033[0;39m"
+RED="\\033[1;31m"
+
+load_module()
+{
+    insmod $1
+    if [ $? -ne 0 ]; then
+	echo -e $RED
+	echo "unable to insmod $1 (err : $?)"
+	echo -e $NORMAL
+	exit $?
+    fi
+}
+
+
+load_module /lib/modules/matcp_core.ko
+load_module /lib/modules/mausb.ko
+#load_module /lib/modules/mamed.ko
+load_module /lib/modules/matcp_host.ko
+
+mknod /dev/mausb c 100 0
+
+echo -e $GREEN
+echo "mausb load process complete"
+echo -e $NORMAL
diff --git a/drivers/staging/mausb/scripts/load_mausb_android.sh b/drivers/staging/mausb/scripts/load_mausb_android.sh
new file mode 100755
index 0000000..57f119e
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_mausb_android.sh
@@ -0,0 +1,33 @@
+#!/system/xbin/ash
+
+# For Android targets, insmod shall be used since
+# the ueventd take care of the dependencies.
+
+GREEN="\\033[1;32m"
+NORMAL="\\033[0;39m"
+RED="\\033[1;31m"
+
+load_module()
+{
+    insmod $1
+    if [ $? -ne 0 ]; then
+	echo -e $RED
+	echo "unable to insmod $1 (err : $?)"
+	echo -e $NORMAL
+	exit $?
+    fi
+}
+
+
+load_module /lib/modules/matcp_core.ko
+load_module /lib/modules/mausb.ko
+load_module /lib/modules/maudc.ko
+#load_module /lib/modules/mamed.ko
+load_module /lib/modules/matcp_host.ko
+load_module /lib/modules/matcp_dev.ko
+
+mknod /dev/mausb c 100 0
+
+echo -e $GREEN
+echo "mausb load process complete"
+echo -e $NORMAL
\ No newline at end of file
diff --git a/drivers/staging/mausb/scripts/load_script.sh b/drivers/staging/mausb/scripts/load_script.sh
new file mode 100755
index 0000000..7c92afa
--- /dev/null
+++ b/drivers/staging/mausb/scripts/load_script.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+# This script is used for loading & unloading the mausb_driver
+
+# note: this script must be run with root priviledge (for the modprobes)
+
+side="invalid"
+mode="invalid"
+load="load"
+
+# Determine weather to load a host or device in TCP mode or snap mode
+while getopts "hdbtslu" opt; do
+	case "$opt" in
+	h) side="host"
+	   ;;
+	d) side="device"
+	   ;;
+	b) side="both"
+	   ;;
+	t) mode="tcp"
+	   ;;
+	s) mode="snap"
+	   ;;
+	l) load="load"
+	   ;;
+	u) load="unload"
+	   ;;
+	esac
+done
+
+if [ "$side" == "invalid" ]
+then
+	echo $side
+	echo "please choose host (-h) or device (-d)"
+	exit
+fi
+
+if [ "$mode" == "invalid" ]
+then
+	echo $mode
+	echo "please choose a tcp (-t) or snap (-s)"
+	exit
+fi
+
+
+
+if [ "$load" == "load" ]
+then
+	# copy the LKM into the module library
+	pushd $(dirname $0)
+	cp ../drivers/*.ko /lib/modules/$(uname -r)/kernel/drivers/usb/
+	popd
+
+	# depmod so the kernel can figure out its dependacies
+	depmod -A
+
+	# open the file for ioctl calls
+	mknod /dev/mausb c 100 0
+
+	modprobe_flags=""
+
+elif [ "$load" == "unload" ]
+then
+	# unload the drivers instead of loading them
+	modprobe_flags="-r"
+
+fi
+
+
+
+# load the drivers
+
+if [ "$mode" == "tcp" ] && [ "$load" == "load" ]
+then
+	modprobe $modprobe_flags matcp_core
+
+elif [ "$mode" == "snap" ]
+then
+	modprobe $modprobe_flags masnap_core
+fi
+
+
+if [ "$side" == "device" ] || [ "$side" == "both" ]
+then
+	if [ "$load" == "load" ]
+	then
+		modprobe $modprobe_flags maudc
+	fi
+
+	modprobe $modprobe_flags g_zero
+
+	if [ "$mode" == "tcp" ]
+	then
+		modprobe $modprobe_flags matcp_dev
+
+	elif [ "$mode" == "snap" ]
+	then
+		modprobe $modprobe_flags masnap_dev
+	fi
+fi
+
+if [ "$side" == "host" ] || [ "$side" == "both" ]
+then
+	if [ "$load" == "load" ]
+	then
+		modprobe $modprobe_flags mausb
+	fi
+
+	if [ "$mode" == "tcp" ]
+	then
+		modprobe $modprobe_flags matcp_host
+
+	elif [ "$mode" == "snap" ]
+	then
+		modprobe $modprobe_flags masnap_host
+	fi
+
+fi
+
+if [ "$load" == "unload" ]
+then
+	modprobe $modprobe_flags maudc
+	modprobe $modprobe_flags mausb
+fi
+
+echo "$load mausb $side $mode driver complete"
diff --git a/drivers/staging/mausb/scripts/modprobify.sh b/drivers/staging/mausb/scripts/modprobify.sh
new file mode 100755
index 0000000..b5f16ab
--- /dev/null
+++ b/drivers/staging/mausb/scripts/modprobify.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+
+# note: this scripted needs to be run as a superuser to work
+
+# copy the LKM into the module library
+cp ./*.ko /lib/modules/$(uname -r)/kernel/drivers/usb/
+
+# depmod so the kernel can figure out its dependacies
+depmod -A
diff --git a/drivers/staging/mausb/scripts/unload_gzero.sh b/drivers/staging/mausb/scripts/unload_gzero.sh
new file mode 100755
index 0000000..e506b2d
--- /dev/null
+++ b/drivers/staging/mausb/scripts/unload_gzero.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+modprobe -r g_zero
+
+echo g_zero unload process complete
\ No newline at end of file
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [V2 PATCH 10/10] added kernel build, configuration, and TODO files
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (7 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
@ 2014-11-11  2:09   ` Stephanie Wallick
  2014-11-11  4:23     ` Greg KH
  2014-11-11  4:08   ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Greg KH
  2014-11-11 15:54   ` Alan Stern
  10 siblings, 1 reply; 54+ messages in thread
From: Stephanie Wallick @ 2014-11-11  2:09 UTC (permalink / raw)
  To: linux-kernel; +Cc: gregkh, linux-usb, devel, Sean O. Stalley

Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
---
 MAINTAINERS                            |  7 +++++++
 drivers/staging/Kconfig                |  2 ++
 drivers/staging/Makefile               |  1 +
 drivers/staging/mausb/Kconfig          | 16 ++++++++++++++++
 drivers/staging/mausb/Makefile         |  2 ++
 drivers/staging/mausb/TODO             |  5 +++++
 drivers/staging/mausb/drivers/Kconfig  | 34 ++++++++++++++++++++++++++++++++++
 drivers/staging/mausb/drivers/Makefile | 18 ++++++++++++++++++
 8 files changed, 85 insertions(+)
 create mode 100644 drivers/staging/mausb/Kconfig
 create mode 100644 drivers/staging/mausb/Makefile
 create mode 100644 drivers/staging/mausb/TODO
 create mode 100644 drivers/staging/mausb/drivers/Kconfig
 create mode 100644 drivers/staging/mausb/drivers/Makefile

diff --git a/MAINTAINERS b/MAINTAINERS
index c3cfa1b..bd52ec2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8721,6 +8721,13 @@ W:	http://www.lirc.org/
 S:	Odd Fixes
 F:	drivers/staging/media/lirc/
 
+STAGING - MEDIA AGNOSTIC USB DRIVERS
+M:	Sean O. Stalley <sean.stalley@intel.com>
+M:	Stephanie Wallick <stephanie.s.wallick@intel.com>
+L:	linux-usb@vger.kernel.org
+S:	Maintained
+F:	drivers/staging/mausb
+
 STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
 M:	Julian Andres Klode <jak@jak-linux.org>
 M:	Marc Dietrich <marvin24@gmx.de>
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 35b494f..f57621b 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,6 +24,8 @@ menuconfig STAGING
 
 if STAGING
 
+source "drivers/staging/mausb/Kconfig"
+
 source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e66a5db..7615c85 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_GS_FPGABOOT)	+= gs_fpgaboot/
 obj-$(CONFIG_BT_NOKIA_H4P)	+= nokia_h4p/
 obj-$(CONFIG_CRYPTO_SKEIN)	+= skein/
 obj-$(CONFIG_UNISYSSPAR)	+= unisys/
+obj-$(CONFIG_MAUSB)		+= mausb/
diff --git a/drivers/staging/mausb/Kconfig b/drivers/staging/mausb/Kconfig
new file mode 100644
index 0000000..095c08b
--- /dev/null
+++ b/drivers/staging/mausb/Kconfig
@@ -0,0 +1,16 @@
+
+menuconfig MAUSB
+	bool "MA USB drivers"
+	depends on USB
+	---help---
+	  This option allows you to select from the various MA USB
+	  drivers. Note that a media-specific driver (e.g. tcp or SNAP)
+	  is needed in addition to the media agnostic host or device driver.
+
+
+if MAUSB
+
+source "drivers/staging/mausb/drivers/Kconfig"
+
+endif
+
diff --git a/drivers/staging/mausb/Makefile b/drivers/staging/mausb/Makefile
new file mode 100644
index 0000000..fc09fb5
--- /dev/null
+++ b/drivers/staging/mausb/Makefile
@@ -0,0 +1,2 @@
+obj-y += drivers/
+
diff --git a/drivers/staging/mausb/TODO b/drivers/staging/mausb/TODO
new file mode 100644
index 0000000..710ee936
--- /dev/null
+++ b/drivers/staging/mausb/TODO
@@ -0,0 +1,5 @@
+TODO:
+	- checkpatch.pl cleanups
+	- address miscellaneous "TODO" statements in code
+	- add support for multiple media agnostic (MA) devices
+	- add/improve support for unimplemented packet types
diff --git a/drivers/staging/mausb/drivers/Kconfig b/drivers/staging/mausb/drivers/Kconfig
new file mode 100644
index 0000000..9e12e22
--- /dev/null
+++ b/drivers/staging/mausb/drivers/Kconfig
@@ -0,0 +1,34 @@
+config MA_CORE
+	tristate "MA USB core"
+	---help---
+	  This builds ma_core module.
+
+config MAUSB_HOST
+	tristate "MA USB host"
+	depends on MA_CORE
+	---help---
+	  This builds MA USB host driver module.
+
+config MAUSB_DEVICE
+	tristate "MA USB device"
+	depends on MA_CORE && USB_GADGET
+	---help---
+	  This builds MA USB device driver module.
+
+config MATCP_CORE
+	tristate "MA USB tcp core"
+	---help---
+	  This builds tcp_core module.
+
+config MATCP_HOST
+	tristate "MA USB host tcp"
+	depends on MATCP_CORE
+	---help---
+	  This builds tcp_host module.
+
+config MATCP_DEVICE
+	tristate "MA USB device tcp"
+	depends on MATCP_CORE
+	---help---
+	  This builds tcp_dev module.
+
diff --git a/drivers/staging/mausb/drivers/Makefile b/drivers/staging/mausb/drivers/Makefile
new file mode 100644
index 0000000..47f3222
--- /dev/null
+++ b/drivers/staging/mausb/drivers/Makefile
@@ -0,0 +1,18 @@
+obj-$(CONFIG_MA_CORE) += ma_core.o
+ma_core-y := mausb_pkt.o mausb_tx.o mausb_msapi.o mausb_mem.o mausb_mgmt.o
+
+obj-$(CONFIG_MAUSB_HOST) += mausb.o
+mausb-y := mausb_hcd.o mausb_hub.o mausb_tx-host.o mausb_mem-host.o
+
+obj-$(CONFIG_MAUSB_DEVICE) += maudc.o
+maudc-y := mausb_udc.o mausb_tx-device.o
+
+obj-$(CONFIG_MATCP_HOST) += matcp_host.o
+matcp_host-y := mausb_tcp-host.o
+
+obj-$(CONFIG_MATCP_DEVICE) += matcp_dev.o
+matcp_dev-y := mausb_tcp-device.o
+
+obj-$(CONFIG_MATCP_CORE) += matcp_core.o
+matcp_core-y := mausb_tcp.o mausb_ioctl.o
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (8 preceding siblings ...)
  2014-11-11  2:09   ` [V2 PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
@ 2014-11-11  4:08   ` Greg KH
  2014-11-11 15:54   ` Alan Stern
  10 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-11  4:08 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, linux-usb, devel, Sean O. Stalley

On Mon, Nov 10, 2014 at 06:09:32PM -0800, Stephanie Wallick wrote:
> +static int mausb_bus_probe(struct device *dev)
> +{
> +	return mausb_probe(dev);
> +}
> +
> +static int mausb_bus_remove(struct device *dev)
> +{
> +	return mausb_remove(dev);
> +}

Wrapper functions that just call another function?  Why?

> +static void mausb_dev_release(struct device *dev)
> +{
> +	/* TODO: if we dynamically allocate anything, free it here */
> +}

As per the documentation in the kernel source tree[1], I am now allowed
to mock you mercilessly for thinking that you know more than the kernel,
and are just providing an "empty" function just to shut it up from
complaining about no release function at all.  Did you stop to think
about _why_ the kernel was warning you about this, and how would an
empty function solve anything?

Sorry, I can never accept code that does this in the kernel, even in
staging, which says a lot...

thanks,

greg k-h

[1] Documentation/kobject.txt, line 270

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-11  2:09   ` [V2 PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
@ 2014-11-11  4:21     ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-11  4:21 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, linux-usb, devel, Sean O. Stalley

On Mon, Nov 10, 2014 at 06:09:36PM -0800, Stephanie Wallick wrote:
> +static int ma_open;

Why do you need this variable?

> +/**
> + * This function is used to open the device file in order to read/write
> + * from/to it.
> + *
> + * @inode:	Struct with various information that is passed in when this
> + *		function is called. We don't need to use it for our purposes.
> + * @file:	The file to be opened.
> + */
> +static int mausb_open(struct inode *inode, struct file *file)
> +{
> +	if (ma_open)
> +		return -EBUSY;
> +	ma_open++;

Racy :(

> +	try_module_get(THIS_MODULE);

Even more racy, _NEVER_ make this type of call, it's _ALWAYS_ wrong.

And totally not even needed at all, if you set up your file structure
properly.

> +
> +	return 0;
> +}
> +
> +/**
> + * This function is used to close the device file.
> + *
> + * @inode:	Struct with various information that is passed in when this
> + *		function is called. We don't need to use it for our purposes.
> + * @file:	The file to be closed.
> + */
> +static int mausb_release(struct inode *inode, struct file *file)
> +{
> +	ma_open--;

Again, racy, and pointless, why are you doing this?

> +	module_put(THIS_MODULE);

And again, broken and racy :(

> +	return 0;
> +}
> +
> +
> +/**
> + * This function is used to execute ioctl commands, determined by ioctl_func.
> + *
> + * @file:	  The device file. We don't use it directly, but it's passed in.
> + * @ioctl_func:	  This value determines which ioctl function will be used.
> + * @ioctl_buffer: This buffer is used to transfer data to/from the device.
> + */
> +long mausb_ioctl(struct file *file, unsigned int ioctl_func,
> +		unsigned long ioctl_buffer)
> +{
> +	char message[BUFFER];
> +	int ret, value;
> +	unsigned long int long_value;
> +	char __user *msg = (char *)ioctl_buffer;
> +	char *response;
> +
> +	switch (ioctl_func) {
> +	case IOCTL_GET_VRSN:
> +		ret = copy_to_user(msg, DRIVER_VERSION, strlen(DRIVER_VERSION));
> +		break;

This should be a sysfs file.  Why even care about the version?


> +	case IOCTL_GET_NAME:
> +		ret = copy_to_user(msg, MAUSB_NAME, strlen(MAUSB_NAME));
> +		break;

Why?

> +	case IOCTL_GADGET_C:
> +		ret = gadget_connection(1);
> +		if (ret >= 0)
> +			response = MAUSB_GADGET_C_SUCCESS;
> +		else
> +			response = MAUSB_GADGET_C_FAIL;
> +
> +		ret = copy_to_user(msg, response, strlen(response));
> +		break;

Can't this be a sysfs file?

> +	case IOCTL_GADGET_D:
> +		ret = gadget_connection(0);
> +		if (ret >= 0)
> +			response = MAUSB_GADGET_D_SUCCESS;
> +		else
> +			response = MAUSB_GADGET_D_FAIL;
> +
> +		ret = copy_to_user(msg, response, strlen(response));
> +		break;

Same here.


> +	case IOCTL_SET_PORT:
> +		ret = strncpy_from_user(message, msg, BUFFER);
> +		if (ret < 0)
> +			break;
> +		ret = kstrtoint(msg, 0, &value);
> +		if (ret != 0)
> +			break;
> +
> +		ret = set_port_no(value);
> +		sprintf(message, "PORT NUMBER:%d, Returned %i\n", value,
> +			ret);

That looks like a debug message.

> +		ret = copy_to_user(msg, message, strlen(message));
> +		break;

That really looks like a sysfs file.


> +	case IOCTL_SET_IP:
> +		ret = strncpy_from_user(message, msg, BUFFER);
> +		if (ret < 0)
> +			break;
> +		ret = kstrtoul(message, 0, &long_value);
> +		if (ret != 0)
> +			break;
> +
> +		ret = set_ip_addr(long_value);
> +		sprintf(message, "IP ADDRESS:%lx, returned %i\n",
> +			long_value, ret);

That looks like a debug message :(

> +		ret = copy_to_user(msg, message, strlen(message));
> +		break;

again sysfs file?


> +	case IOCTL_SET_MAC:
> +		{
> +			u8 mac[6];
> +			int i;
> +			ret = copy_from_user(mac, msg, 6);
> +			if (ret) {
> +				pr_err("copy_from_user failed\n");
> +				break;
> +			}
> +			for (i = 0; i < ETH_ALEN; i++)
> +				pr_info("mac[%d]=0x%x\n", i, mac[i]);
> +			ret = set_mac_addr(mac);
> +			if (ret)
> +				pr_err("unable to set MAC addr\n");
> +
> +			break;
> +		}

And again, sysfs file.

What about any other ioctl?  You forgot to return an invalid number.

> +	}
> +
> +	/* failure */
> +	if (ret < 0)
> +		return ret;

You could have just returned a stack value here :(


> +
> +	/* success */
> +	return 0;

No need for the comments, this is a pretty common kernel idiom,
especially when all 6 lines get reduced to a single 'return ret;' line :)


> +}
> +
> +/**
> + * This struct creates links with our implementations of various entry point
> + * functions.
> + */
> +const struct file_operations fops = {
> +	.open = mausb_open,
> +	.release = mausb_release,
> +	.unlocked_ioctl = mausb_ioctl
> +};

Any reason you didn't set the file_operations module owner here?  (hint,
do that and you will never need the crazy try_module_get() crazy
above...)

> +
> +/**
> + * Registers a character device using our device file. This function is called
> + * in the mausb_hcd_init function.
> + */
> +int reg_chrdev()

()???


> +{
> +	int ret;
> +
> +#ifdef MAUSB_PRINT_IOCTL_MAGIC

please no.


> +
> +	printk(KERN_DEBUG "Printing IOCTL magic numbers:\n");
> +	printk(KERN_DEBUG "IOCTL_SET_MSG        = %u\n", IOCTL_SET_MSG);
> +	printk(KERN_DEBUG "IOCTL_GET_MSG        = %u\n", IOCTL_GET_MSG);
> +	printk(KERN_DEBUG "IOCTL_GET_VRSN       = %u\n", IOCTL_GET_VRSN);
> +	printk(KERN_DEBUG "IOCTL_GET_NAME       = %u\n", IOCTL_GET_NAME);
> +	printk(KERN_DEBUG "IOCTL_GADGET_C       = %u\n", IOCTL_GADGET_C);
> +	printk(KERN_DEBUG "IOCTL_GADGET_D       = %u\n", IOCTL_GADGET_D);
> +	printk(KERN_DEBUG "IOCTL_MED_DELAY      = %u\n", IOCTL_MED_DELAY);
> +	printk(KERN_DEBUG "IOCTL_SET_IP         = %u\n", IOCTL_SET_IP);
> +	printk(KERN_DEBUG "IOCTL_SET_PORT       = %u\n", IOCTL_SET_PORT);
> +	printk(KERN_DEBUG "IOCTL_SET_IP_DECIMAL = %u\n", IOCTL_SET_IP_DECIMAL);
> +	printk(KERN_DEBUG "IOCTL_SET_MAC        = %u\n", IOCTL_SET_MAC);
> +
> +#endif
> +
> +	ret = register_chrdev(MAJOR_NUM, MAUSB_NAME, &fops);
> +
> +	if (ret < 0)
> +		printk(KERN_ALERT "Registering mausb failed with %d\n", ret);
> +	else
> +		printk(KERN_INFO "%s registeration complete. Major device"
> +			" number %d.\n", MAUSB_NAME, MAJOR_NUM);
> +
> +	return ret;
> +}
> +
> +/**
> + * Unregisters the character device when the hcd is unregistered. As hinted,
> + * this function is called in the mausb_hcd_exit function.
> + */
> +void unreg_chrdev()

That's a _very_ bold global function name you just chose for this, and
the previous function :(


> +{
> +	unregister_chrdev(MAJOR_NUM, MAUSB_NAME);
> +}
> diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.h b/drivers/staging/mausb/drivers/mausb_ioctl.h
> new file mode 100644
> index 0000000..4126ade
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_ioctl.h
> @@ -0,0 +1,101 @@
> +/* Name:         mausb_ioctl.h
> + * Description:  header file for MA USB ioctl functions
> + *
> + * This file is provided under a dual BSD/GPLv2 license.  When using or
> + * redistributing this file, you may do so under either license.
> + *
> + * GPL LICENSE SUMMARY
> + *
> + * Copyright(c) 2014 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as published
> + * by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * Contact Information:
> + * Sean Stalley, sean.stalley@intel.com
> + * Stephanie Wallick, stephanie.s.wallick@intel.com
> + * 2111 NE 25th Avenue
> + * Hillsboro, Oregon 97124
> + *
> + * BSD LICENSE
> + *
> + * Copyright(c) 2014 Intel Corporation.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> +    * Redistributions of source code must retain the above copyright
> +      notice, this list of conditions and the following disclaimer.
> +    * Redistributions in binary form must reproduce the above copyright
> +      notice, this list of conditions and the following disclaimer in
> +      the documentation and/or other materials provided with the
> +      distribution.
> +    * Neither the name of Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef MAUSB_IOCTL_H
> +#define MAUSB_IOCTL_H
> +
> +#define BUFFER 80

Why 80?  Why not 8000?  Why any number at all?

> +#define DRIVER_VERSION "Alpha 0.0.25"

Why is this even needed?

> +#define MAJOR_NUM 100

You can't just steal another driver's major number, that's not allowed
at all, and again, something I can never even accept into the staging
tree.

Why need a reserved major at all?

> +/* These define the ioctl functions that can be used. */
> +#define IOCTL_GET_VRSN _IOR(MAJOR_NUM, 0, char *)
> +#define IOCTL_GET_NAME _IOR(MAJOR_NUM, 1, char *)
> +#define IOCTL_GADGET_C _IOR(MAJOR_NUM, 2, char *)
> +#define IOCTL_GADGET_D _IOR(MAJOR_NUM, 3, char *)
> +#define IOCTL_SET_IP   _IOR(MAJOR_NUM, 4, char *)
> +#define IOCTL_SET_PORT _IOR(MAJOR_NUM, 5, char *)
> +#define IOCTL_SET_MAC  _IOR(MAJOR_NUM, 6, char *)

These are not all _IOR() ioctls, look at the code implementing them!

> +/* This is the location where the device file will be created. It is used to
> + * read/write to in order to communicate to and from the device. */
> +#define DEVICE_FILE_NAME "/dev/mausb"

Never used, don't put that in a kernel file.


> +
> +/* MAC address length */
> +#define ETH_ALEN 6
> +
> +/* Responses to IOCTL calls */
> +#define MAUSB_GADGET_C_SUCCESS	"gadget connect process complete"
> +#define MAUSB_GADGET_C_FAIL	"gadget connect process failed"
> +#define MAUSB_GADGET_D_SUCCESS	"gadget disconnect process complete"
> +#define MAUSB_GADGET_D_FAIL	"gadget disconnect process failed"

ioctls returning text strings?  Next thing you will want i18n versions
of them...

> +int mausb_transfer_packet(struct ms_pkt *pkt,
> +	struct mausb_pkt_transfer *transfer)
> +{
> +	return transfer->transfer_packet(pkt, transfer->context);
> +}
> +EXPORT_SYMBOL(mausb_transfer_packet);

EXPORT_SYMBOL_GPL() for USB stuff please.

I'm not reviewing further, sorry.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 10/10] added kernel build, configuration, and TODO files
  2014-11-11  2:09   ` [V2 PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
@ 2014-11-11  4:23     ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2014-11-11  4:23 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, devel, linux-usb, Sean O. Stalley

On Mon, Nov 10, 2014 at 06:09:41PM -0800, Stephanie Wallick wrote:
> Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
> Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>

No changelog entry?


> ---
>  MAINTAINERS                            |  7 +++++++
>  drivers/staging/Kconfig                |  2 ++
>  drivers/staging/Makefile               |  1 +
>  drivers/staging/mausb/Kconfig          | 16 ++++++++++++++++
>  drivers/staging/mausb/Makefile         |  2 ++
>  drivers/staging/mausb/TODO             |  5 +++++
>  drivers/staging/mausb/drivers/Kconfig  | 34 ++++++++++++++++++++++++++++++++++
>  drivers/staging/mausb/drivers/Makefile | 18 ++++++++++++++++++
>  8 files changed, 85 insertions(+)
>  create mode 100644 drivers/staging/mausb/Kconfig
>  create mode 100644 drivers/staging/mausb/Makefile
>  create mode 100644 drivers/staging/mausb/TODO
>  create mode 100644 drivers/staging/mausb/drivers/Kconfig
>  create mode 100644 drivers/staging/mausb/drivers/Makefile
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c3cfa1b..bd52ec2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8721,6 +8721,13 @@ W:	http://www.lirc.org/
>  S:	Odd Fixes
>  F:	drivers/staging/media/lirc/
>  
> +STAGING - MEDIA AGNOSTIC USB DRIVERS
> +M:	Sean O. Stalley <sean.stalley@intel.com>
> +M:	Stephanie Wallick <stephanie.s.wallick@intel.com>
> +L:	linux-usb@vger.kernel.org
> +S:	Maintained
> +F:	drivers/staging/mausb
> +
>  STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
>  M:	Julian Andres Klode <jak@jak-linux.org>
>  M:	Marc Dietrich <marvin24@gmx.de>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index 35b494f..f57621b 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -24,6 +24,8 @@ menuconfig STAGING
>  
>  if STAGING
>  
> +source "drivers/staging/mausb/Kconfig"
> +
>  source "drivers/staging/et131x/Kconfig"
>  
>  source "drivers/staging/slicoss/Kconfig"

Please put yourself at the end, not the top of this file.
> --- /dev/null
> +++ b/drivers/staging/mausb/TODO
> @@ -0,0 +1,5 @@
> +TODO:
> +	- checkpatch.pl cleanups
> +	- address miscellaneous "TODO" statements in code
> +	- add support for multiple media agnostic (MA) devices
> +	- add/improve support for unimplemented packet types

What about the other comments you already received such as:
	- unify with usbip



> diff --git a/drivers/staging/mausb/drivers/Kconfig b/drivers/staging/mausb/drivers/Kconfig
> new file mode 100644
> index 0000000..9e12e22
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/Kconfig
> @@ -0,0 +1,34 @@
> +config MA_CORE
> +	tristate "MA USB core"
> +	---help---
> +	  This builds ma_core module.
> +
> +config MAUSB_HOST
> +	tristate "MA USB host"
> +	depends on MA_CORE
> +	---help---
> +	  This builds MA USB host driver module.
> +
> +config MAUSB_DEVICE
> +	tristate "MA USB device"
> +	depends on MA_CORE && USB_GADGET
> +	---help---
> +	  This builds MA USB device driver module.
> +
> +config MATCP_CORE
> +	tristate "MA USB tcp core"
> +	---help---
> +	  This builds tcp_core module.
> +
> +config MATCP_HOST
> +	tristate "MA USB host tcp"
> +	depends on MATCP_CORE
> +	---help---
> +	  This builds tcp_host module.
> +
> +config MATCP_DEVICE
> +	tristate "MA USB device tcp"
> +	depends on MATCP_CORE
> +	---help---
> +	  This builds tcp_dev module.
> +
> diff --git a/drivers/staging/mausb/drivers/Makefile b/drivers/staging/mausb/drivers/Makefile
> new file mode 100644
> index 0000000..47f3222
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/Makefile
> @@ -0,0 +1,18 @@
> +obj-$(CONFIG_MA_CORE) += ma_core.o
> +ma_core-y := mausb_pkt.o mausb_tx.o mausb_msapi.o mausb_mem.o mausb_mgmt.o
> +
> +obj-$(CONFIG_MAUSB_HOST) += mausb.o
> +mausb-y := mausb_hcd.o mausb_hub.o mausb_tx-host.o mausb_mem-host.o
> +
> +obj-$(CONFIG_MAUSB_DEVICE) += maudc.o
> +maudc-y := mausb_udc.o mausb_tx-device.o
> +
> +obj-$(CONFIG_MATCP_HOST) += matcp_host.o
> +matcp_host-y := mausb_tcp-host.o
> +
> +obj-$(CONFIG_MATCP_DEVICE) += matcp_dev.o
> +matcp_dev-y := mausb_tcp-device.o
> +
> +obj-$(CONFIG_MATCP_CORE) += matcp_core.o
> +matcp_core-y := mausb_tcp.o mausb_ioctl.o

Why so many different modules?  Can't you merge most of these together
as you can't do anything with just a few of them alone.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-11  2:09   ` [V2 PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
@ 2014-11-11  4:38     ` Greg KH
  2014-11-11 22:42       ` Sean O. Stalley
  0 siblings, 1 reply; 54+ messages in thread
From: Greg KH @ 2014-11-11  4:38 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, linux-usb, devel, Sean O. Stalley

On Mon, Nov 10, 2014 at 06:09:34PM -0800, Stephanie Wallick wrote:
> +/**
> + * Returns the number of urbs currently in the MA USB HCD. Will return 0 if the
> + * MA USB HCD is empty or a negative errno if an error occurs.

How can this function return a negative number?  I don't see that
codepath here, can you show it to me?

> + */
> +int mausb_hcd_urb_count(struct mausb_hcd *mhcd)
> +{
> +	int			count = 0;
> +	struct mausb_host_ep	*ma_ep;
> +	struct mausb_dev	*mausb_dev;
> +	struct mausb_urb	*maurb;
> +	unsigned long		irq_flags;
> +
> +	/* for every device */
> +	spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
> +	list_for_each_entry(mausb_dev, &mhcd->ma_dev.dev_list, dev_list) {
> +		spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
> +
> +		/* for every endpoint */
> +		spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
> +		list_for_each_entry(ma_ep, &mausb_dev->ep_list, ep_list) {
> +			spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
> +
> +			/* for every urb */
> +			spin_lock_irqsave(&ma_ep->ep_lock, irq_flags);
> +			list_for_each_entry(maurb, &ma_ep->urb_list, urb_list) {
> +				++count;
> +			}
> +
> +			spin_unlock_irqrestore(&ma_ep->ep_lock, irq_flags);
> +			spin_lock_irqsave(&mausb_dev->dev_lock, irq_flags);
> +		}
> +
> +		spin_unlock_irqrestore(&mausb_dev->dev_lock, irq_flags);
> +		spin_lock_irqsave(&mhcd->hcd_lock, irq_flags);
> +	}
> +
> +	spin_unlock_irqrestore(&mhcd->hcd_lock, irq_flags);
> +
> +	return count;
> +}

There honestly is too many things wrong with this function to even know
where to start.  So how about I just ask why you would ever want to know
this number, and what good it would do to even care about it?  You do
realize that this number is almost always guaranteed to be wrong once
the function returns, so you better not be doing something with it that
matters.

Intel has a whole group of very experienced Linux kernel developers who
will review code before you sent it out publicly.  Please take advantage
of them and run this all through them before resending this out again.

If you did run this code through that group, please let me know who it
was specifically that allowed this stuff to get through, and why they
didn't want their name on this code submission.  I need to have a strong
word with them...

Yes, I am holding you to a higher standard than staging code normally
is, and yes, it is purely because of the company you work for.  But I
only do that because your company knows how to do this stuff right, and
you have access to the resources and talent to help make this code
right.  Other people and companies do not have the kind of advantage
that you do.

Wasting community member's time (i.e. mine) by forcing _them_ to review
stuff like this, is something that your company knows better than to do,
as should you as well.

I want to see some more senior Intel kernel developer's signed-off-by
lines on this code before I will ever consider accepting it for the
kernel.  Please do not resend this code until that happens.

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
                     ` (9 preceding siblings ...)
  2014-11-11  4:08   ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Greg KH
@ 2014-11-11 15:54   ` Alan Stern
  2014-11-12 21:40     ` Sean O. Stalley
  10 siblings, 1 reply; 54+ messages in thread
From: Alan Stern @ 2014-11-11 15:54 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, gregkh, linux-usb, devel, Sean O. Stalley

On Mon, 10 Nov 2014, Stephanie Wallick wrote:

> +static struct mausb_hcd mhcd;

Only one statically-allocated structure?  What if somebody wants to 
have more than one of these things in their system?

> +/**
> + * @maurb:	Media agnostic structure with URB to release.
> + * @status:	Status for URB that is getting released.
> + *
> + * Removes an URB from the queue, deletes the media agnostic information in
> + * the urb, and gives the URB back to the HCD. Caller must be holding the
> + * driver's spinlock.
> + */
> +void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status)
> +{
> +	struct urb		*urb;
> +	struct usb_hcd		*hcd;
> +	struct api_context	*ctx = NULL;
> +	unsigned long		irq_flags;
> +
> +	hcd = mausb_hcd_to_usb_hcd(&mhcd);
> +
> +	spin_lock_irqsave(&mhcd.giveback_lock, irq_flags);

Why do you need multiple spinlocks?  Isn't one lock sufficient?

> +	if (!maurb) {
> +		mausb_err(&mhcd, "%s: no maurb\n", __func__);
> +		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> +		return;
> +	} else {
> +		urb = maurb->urb;
> +		ctx = urb->context;
> +	}
> +
> +	if (!urb) {
> +		mausb_err(&mhcd, "%s: no urb\n", __func__);
> +		mausb_internal_drop_maurb(maurb, &mhcd);
> +		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> +		return;
> +	}
> +
> +	mausb_dbg(&mhcd, "%s: returning urb with status %i\n", __func__, status);
> +
> +	usb_hcd_unlink_urb_from_ep(hcd, urb);
> +	usb_hcd_giveback_urb(hcd, urb, status);

You must not call this function while holding any spinlocks.  What happens
if the URB's completion routine tries to resubmit?

> +
> +	/* remove the mausb-specific data */
> +	mausb_internal_drop_maurb(maurb, &mhcd);
> +
> +	spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> +}
> +
> +/**
> + * Adds an URB to the endpoint queue then calls the URB handler. URB is wrapped
> + * in media agnostic structure before being enqueued.
> + */
> +static int mausb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
> +		gfp_t memflags)
> +{
> +	int			ret = 0;
> +	struct mausb_urb	*maurb;
> +	struct mausb_host_ep	*ep;
> +	unsigned long		irq_flags;
> +
> +	if (!hcd || !urb) {
> +		pr_err("%s: no %s\n", __func__, (hcd ? "urb" : "USB hcd"));
> +	}

This can never happen.  The USB core guarantees it; you don't need 
to check.

> +	ep   = usb_to_ma_endpoint(urb->ep);
> +
> +	if (!ep) {
> +		mausb_err(&mhcd, "%s: no endpoint\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (urb->status != -EINPROGRESS) {
> +		mausb_err(&mhcd, "%s: urb already unlinked, status is %i\n",
> +			__func__, urb->status);
> +		return urb->status;
> +	}

You also don't need to check this.

> +	/* If the endpoint isn't activated, we can't enqueue anything. */
> +	if (MAUSB_EP_HANDLE_UNASSIGNED == ep->ep_handle_state) {
> +		mausb_err(&mhcd, "%s: endpoint handle unassigned\n", __func__);
> +		return -EPIPE;
> +	}
> +
> +	if (USB_SPEED_FULL != urb->dev->speed) /* suppress checks */
> +		ep->max_pkt = usb_endpoint_maxp(&urb->ep->desc);

What happens to full-speed devices?  Don't they have maxpacket values?

> +
> +	/* initialize the maurb */
> +	maurb = mausb_alloc_maurb(ep, memflags);
> +	if (!maurb) {
> +		mausb_err(&mhcd, "could not allocate memory for MA USB urb\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* set maurb member values */
> +	maurb->urb = urb;
> +	urb->hcpriv = maurb;
> +
> +	/* submit urb to hcd and add to endpoint queue */
> +	ret = usb_hcd_link_urb_to_ep(hcd, urb);

Read the kerneldoc for this function.  You must hold your private
spinlock when you call it.

> +	if (ret < 0) {
> +		mausb_err(&mhcd, "urb enqueue failed: error %d\n", ret);
> +		usb_hcd_unlink_urb_from_ep(hcd, urb);
> +		return ret;
> +	}
> +
> +	/* get usb device and increment reference counter */
> +	if (!mhcd.udev) {
> +		mhcd.udev = urb->dev;
> +		usb_get_dev(mhcd.udev);
> +	}

What happens if more than one device is in use at a time?

> +
> +	/* add urb to queue list */
> +	spin_lock_irqsave(&ep->ep_lock, irq_flags);
> +	list_add_tail(&maurb->urb_list, &ep->urb_list);
> +	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);

Yet another class of spinlocks!

> +	/* add urb to ma hcd urb list */
> +	spin_lock_irqsave(&mhcd.urb_list_lock, irq_flags);

And another!  You really shouldn't need more than one lock.

> +	list_add_tail(&maurb->ma_hcd_urb_list, &mhcd.enqueue_urb_list);
> +	spin_unlock_irqrestore(&mhcd.urb_list_lock, irq_flags);
> +
> +	/* send to MA transfer process */
> +	wake_up(&mhcd.waitq);
> +
> +	return ret;
> +}
> +
> +/**
> + * Dequeues an URB.
> + */
> +static int mausb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
> +{
> +	int			ret	= 0;
> +	struct mausb_host_ep	*ep = usb_to_ma_endpoint(urb->ep);
> +	struct mausb_urb	*maurb = usb_urb_to_mausb_urb(urb);
> +	unsigned long		irq_flags;
> +
> +	/* For debugging - we want to know who initiated URB dequeue. */
> +	dump_stack();

Debugging things like this should be removed before a patch is submitted.

That's enough for now.  Obviously there are a lot of issues in this 
driver which need to be fixed up.

Alan Stern



^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-11  4:38     ` Greg KH
@ 2014-11-11 22:42       ` Sean O. Stalley
  2014-11-12  1:14         ` Greg KH
  0 siblings, 1 reply; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-11 22:42 UTC (permalink / raw)
  To: Greg KH; +Cc: Stephanie Wallick, linux-kernel, linux-usb, devel

On Tue, Nov 11, 2014 at 01:38:21PM +0900, Greg KH wrote:
> On Mon, Nov 10, 2014 at 06:09:34PM -0800, Stephanie Wallick wrote:
> Intel has a whole group of very experienced Linux kernel developers who
> will review code before you sent it out publicly.  Please take advantage
> of them and run this all through them before resending this out again.
> 
> If you did run this code through that group, please let me know who it
> was specifically that allowed this stuff to get through, and why they
> didn't want their name on this code submission.  I need to have a strong
> word with them...

We submitted the patches for internal review and got no objections to
release. We will be more aggressive in seeking out feedback (and approval)
before resubmitting any code.
 
> Yes, I am holding you to a higher standard than staging code normally
> is, and yes, it is purely because of the company you work for.  But I
> only do that because your company knows how to do this stuff right, and
> you have access to the resources and talent to help make this code
> right.  Other people and companies do not have the kind of advantage
> that you do.

We know we are fortunate to work for a company with so much talent and
resources and we don't mind being held to a higher standard. We have been
receiving multiple requests for our host driver and wanted to make it
available as soon as possible for others to use. We thought putting our
host driver into staging would be a good way to release it, but realize now
that it was premature. 

> Wasting community member's time (i.e. mine) by forcing _them_ to review
> stuff like this, is something that your company knows better than to do,
> as should you as well.
> 
> I want to see some more senior Intel kernel developer's signed-off-by
> lines on this code before I will ever consider accepting it for the
> kernel.  Please do not resend this code until that happens.
> 
> greg k-h

We apologize for wasting everyone's time and will certainly learn from this.
We won't resubmit the driver until a senior kernel developer has signed off on it.

Sincerely,
Sean O. Stalley
Stephanie S. Wallick

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-11 22:42       ` Sean O. Stalley
@ 2014-11-12  1:14         ` Greg KH
  2014-11-12  2:01           ` steph
  0 siblings, 1 reply; 54+ messages in thread
From: Greg KH @ 2014-11-12  1:14 UTC (permalink / raw)
  To: Sean O. Stalley; +Cc: devel, linux-usb, Stephanie Wallick, linux-kernel

On Tue, Nov 11, 2014 at 02:42:22PM -0800, Sean O. Stalley wrote:
> On Tue, Nov 11, 2014 at 01:38:21PM +0900, Greg KH wrote:
> > On Mon, Nov 10, 2014 at 06:09:34PM -0800, Stephanie Wallick wrote:
> > Intel has a whole group of very experienced Linux kernel developers who
> > will review code before you sent it out publicly.  Please take advantage
> > of them and run this all through them before resending this out again.
> > 
> > If you did run this code through that group, please let me know who it
> > was specifically that allowed this stuff to get through, and why they
> > didn't want their name on this code submission.  I need to have a strong
> > word with them...
> 
> We submitted the patches for internal review and got no objections to
> release. We will be more aggressive in seeking out feedback (and approval)
> before resubmitting any code.

Fair enough, it seems you took the only available path and submitted it
to the community, which was a good idea, sorry for the rant.  Thanks for
submitting it publicly and not just "waiting forever" like I have seen
some people do in the past.

> > Yes, I am holding you to a higher standard than staging code normally
> > is, and yes, it is purely because of the company you work for.  But I
> > only do that because your company knows how to do this stuff right, and
> > you have access to the resources and talent to help make this code
> > right.  Other people and companies do not have the kind of advantage
> > that you do.
> 
> We know we are fortunate to work for a company with so much talent and
> resources and we don't mind being held to a higher standard. We have been
> receiving multiple requests for our host driver and wanted to make it
> available as soon as possible for others to use. We thought putting our
> host driver into staging would be a good way to release it, but realize now
> that it was premature. 

Does the code even work?  The number of basic mistakes in it seems to
imply that it doesn't, but I could be mistaken.

> We won't resubmit the driver until a senior kernel developer has signed off on it.

Good, go kick some of them and get them to review the code, _after_ at
least addressing the issues that the community has raised, you don't
want to waste their time finding the same things we just did :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 03/10] added media agnostic (MA) data structures and handling
  2014-11-12  1:14         ` Greg KH
@ 2014-11-12  2:01           ` steph
  0 siblings, 0 replies; 54+ messages in thread
From: steph @ 2014-11-12  2:01 UTC (permalink / raw)
  To: Greg KH; +Cc: Sean O. Stalley, devel, linux-usb, linux-kernel

On Wed, Nov 12, 2014 at 10:14:38AM +0900, Greg KH wrote:
> On Tue, Nov 11, 2014 at 02:42:22PM -0800, Sean O. Stalley wrote:
> > On Tue, Nov 11, 2014 at 01:38:21PM +0900, Greg KH wrote:
> > > On Mon, Nov 10, 2014 at 06:09:34PM -0800, Stephanie Wallick wrote:
> > > Yes, I am holding you to a higher standard than staging code normally
> > > is, and yes, it is purely because of the company you work for.  But I
> > > only do that because your company knows how to do this stuff right, and
> > > you have access to the resources and talent to help make this code
> > > right.  Other people and companies do not have the kind of advantage
> > > that you do.
> > 
> > We know we are fortunate to work for a company with so much talent and
> > resources and we don't mind being held to a higher standard. We have been
> > receiving multiple requests for our host driver and wanted to make it
> > available as soon as possible for others to use. We thought putting our
> > host driver into staging would be a good way to release it, but realize now
> > that it was premature. 
> 
> Does the code even work?  The number of basic mistakes in it seems to
> imply that it doesn't, but I could be mistaken.
> 

What is there works, but not everything in the MA USB Spec has been implemented
yet. 

> > We won't resubmit the driver until a senior kernel developer has signed off on it.
> 
> Good, go kick some of them and get them to review the code, _after_ at
> least addressing the issues that the community has raised, you don't
> want to waste their time finding the same things we just did :)
> 

Will do! We will most definitely fix the issues raised by the community before
having anyone else review the code. We appreciate everyone's time and feedback
:)


Thanks,
Stephanie

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs
  2014-11-11  2:09   ` [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
@ 2014-11-12  8:35     ` Oliver Neukum
  2014-11-12 19:28       ` Sean O. Stalley
  0 siblings, 1 reply; 54+ messages in thread
From: Oliver Neukum @ 2014-11-12  8:35 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, gregkh, linux-usb, devel, Sean O. Stalley

On Mon, 2014-11-10 at 18:09 -0800, Stephanie Wallick wrote:
> This is where we implement USB 2.0 and 3.0 roothubs. From the host's
> perspective, hub state is set and tracked just like any other USB roothub.
> Likewise, requests to the roothub appear to be handled like any other wired
> USB request.
> 
> Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
> Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
> ---
>  drivers/staging/mausb/drivers/mausb_hub.c | 849 ++++++++++++++++++++++++++++++
>  drivers/staging/mausb/drivers/mausb_hub.h | 128 +++++
>  2 files changed, 977 insertions(+)
>  create mode 100644 drivers/staging/mausb/drivers/mausb_hub.c
>  create mode 100644 drivers/staging/mausb/drivers/mausb_hub.h
> 
> diff --git a/drivers/staging/mausb/drivers/mausb_hub.c b/drivers/staging/mausb/drivers/mausb_hub.c
> new file mode 100644
> index 0000000..63c0fe4
> --- /dev/null
> +++ b/drivers/staging/mausb/drivers/mausb_hub.c

> +/**
> + * Returns true if the given is the superspeed HCD. Note: The primary HCD is
> + * High Speed and the shared HCD is SuperSpeed.
> + */

Why in that order?

> +bool mausb_is_ss_hcd(struct usb_hcd *hcd)
> +{
> +	if (usb_hcd_is_primary_hcd(hcd))
> +		return false;
> +	else
> +		return true;
> +}



> +
> +/**
> + * Called by usb core when polling for a port status change.
> + *
> + * @hcd:	USB HCD being polled.
> + * @buf:	Holds port status changes (if any).
> + *
> + * Returns zero if there is no status change, otherwise returns number of
> + * bytes in buf. When there is a status change on a port, the bit indexed
> + * at the port number + 1 (e.g. bit 2 for port 1) is set in the buffer.
> + */
> +int mausb_hub_status_data(struct usb_hcd *hcd, char *buf)
> +{
> +	int                      i;
> +	u16                      port_change = 0;
> +	u32                      status = 0;
> +	int                      ret = 1;
> +	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
> +	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
> +
> +	/*
> +	 * Buf should never be more that 2 bytes. USB 3.0 hubs cannot have
> +	 * more than 15 downstream ports.
> +	 */
> +	buf[0] = 0;
> +	if (MAUSB_ROOTHUB_NUM_PORTS > 7) {
> +		buf[1] = 0;
> +		ret++;
> +	}

Endianness bug.

> +
> +	for (i = 0; i < MAUSB_ROOTHUB_NUM_PORTS; i++) {
> +		port_change = roothub->port_status[i].wPortChange;
> +		if (port_change)
> +			status |= (1 << (i + 1));
> +	}
> +
> +	mausb_dbg(mhcd, "%s: hub status is 0x%x\n", __func__, status);
> +
> +	/* hcd might be suspended, resume if there is a status change */
> +	if (mhcd->disabled == 0) {
> +		if ((hcd->state == HC_STATE_SUSPENDED) && status)
> +			usb_hcd_resume_root_hub(hcd);
> +	}
> +
> +	memcpy(buf, (char *)&status, ret);
> +
> +	return status ? ret : 0;
> +}
> +
> +/**
> + * Sets the bitfields in the hub descriptor of the 2.0 root hub. Always
> + * returns zero.
> + */
> +int mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des)
> +{
> +	/* set the values to the default */
> +	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
> +	hub_des->bDescriptorType      = USB_DT_HUB;
> +	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
> +	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
> +	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
> +	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;

Is that descriptor in bus or host endianness?

> +
> +	return 0;
> +}
> +
> +/**
> + * Sets the bitfields in the hub descriptor of the 3.0 root hub. Always
> + * returns zero.

Then why return anything?

> + */
> +int mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des)
> +{
> +	/* set the values to the default */
> +	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
> +	hub_des->bDescriptorType      = USB_DT_SS_HUB;
> +	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
> +	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
> +	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
> +	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
> +
> +	/* USB3-specific parameters */
> +	hub_des->u.ss.bHubHdrDecLat   = MAUSB_ROOTHUB_HDR_DEC_LAT;
> +	hub_des->u.ss.wHubDelay       = MAUSB_ROOTHUB_DELAY;
> +	hub_des->u.ss.DeviceRemovable = MAUSB_ALL_DEV_REMOVABLE;
> +
> +	return 0;
> +}


> +/**
> + * Contains all the structures required to emulate a root hub. One instance
> + * exists per root hub.
> + */
> +struct __attribute__((__packed__)) mausb_root_hub {

Why __packed__ ?
> +
> +	/* hub parameters */
> +	struct usb_hub_descriptor descriptor;
> +	struct usb_hub_status     status;
> +
> +	/* port parameters*/
> +	struct usb_port_status    port_status[MAUSB_ROOTHUB_NUM_PORTS];
> +
> +	/* root hub state */
> +	enum   mausb_rh_state     rh_state;
> +
> +};

	HTH
		Oliver

-- 
Oliver Neukum <oneukum@suse.de>


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 04/10] added media agnostic (MA) USB packet handling
  2014-11-11  2:09   ` [V2 PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
@ 2014-11-12 14:01     ` Oliver Neukum
  0 siblings, 0 replies; 54+ messages in thread
From: Oliver Neukum @ 2014-11-12 14:01 UTC (permalink / raw)
  To: Stephanie Wallick; +Cc: linux-kernel, gregkh, linux-usb, devel, Sean O. Stalley

On Mon, 2014-11-10 at 18:09 -0800, Stephanie Wallick wrote:
> +/**
> + * Compares 2 request IDs. Returns true if a is less than b. Handles
> request id
> + * wraparound.
> + */
> +bool mausb_req_id_lt(u8 a, u8 b)

Unify such functions. It's just silly to have so many of them.

> +/**
> + * Calculates the total length of data contained in an ms_pkt (in
> bytes).
> + * Returns the length of the kvec, or 0 on an error.
> + */
> +static int mausb_ms_data_length(struct ms_pkt *pkt)
> +{
> +       int             i;
> +       int             total_length;
> +       struct kvec     *current_kvec;
> +
> +       for (i = 0; i < pkt->nents; ++i) {
> +               current_kvec = &pkt->kvec[i];
> +               if (NULL == current_kvec)
> +                       return -EINVAL;
> +               else
> +                       total_length += current_kvec->iov_len;
> +       }
> +
> +       return total_length;
> +}
> +

	Regards
		Oliver

-- 
Oliver Neukum <oneukum@suse.de>


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs
  2014-11-12  8:35     ` Oliver Neukum
@ 2014-11-12 19:28       ` Sean O. Stalley
  2014-11-12 19:52         ` Alan Stern
  0 siblings, 1 reply; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-12 19:28 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

Thank you for your review. My responses are inline.

Greg has requested that we clean up the driver internally before
we resubmit another patchset to the mailing list. I will make
sure the changes you requested make it in, but it may be a while
before you see a patchset with the fixes included.

Thanks,
Sean O. Stalley

On Wed, Nov 12, 2014 at 09:35:42AM +0100, Oliver Neukum wrote:
> On Mon, 2014-11-10 at 18:09 -0800, Stephanie Wallick wrote:
> > diff --git a/drivers/staging/mausb/drivers/mausb_hub.c b/drivers/staging/mausb/drivers/mausb_hub.c
> > new file mode 100644
> > index 0000000..63c0fe4
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_hub.c
> 
> > +/**
> > + * Returns true if the given is the superspeed HCD. Note: The primary HCD is
> > + * High Speed and the shared HCD is SuperSpeed.
> > + */
> 
> Why in that order?
> 

We should probably switch this & make the superspeed hub primary.
That way we match the xhci driver.

> > +bool mausb_is_ss_hcd(struct usb_hcd *hcd)
> > +{
> > +	if (usb_hcd_is_primary_hcd(hcd))
> > +		return false;
> > +	else
> > +		return true;
> > +}
> 
> 
> 
> > +
> > +/**
> > + * Called by usb core when polling for a port status change.
> > + *
> > + * @hcd:	USB HCD being polled.
> > + * @buf:	Holds port status changes (if any).
> > + *
> > + * Returns zero if there is no status change, otherwise returns number of
> > + * bytes in buf. When there is a status change on a port, the bit indexed
> > + * at the port number + 1 (e.g. bit 2 for port 1) is set in the buffer.
> > + */
> > +int mausb_hub_status_data(struct usb_hcd *hcd, char *buf)
> > +{
> > +	int                      i;
> > +	u16                      port_change = 0;
> > +	u32                      status = 0;
> > +	int                      ret = 1;
> > +	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
> > +	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
> > +
> > +	/*
> > +	 * Buf should never be more that 2 bytes. USB 3.0 hubs cannot have
> > +	 * more than 15 downstream ports.
> > +	 */
> > +	buf[0] = 0;
> > +	if (MAUSB_ROOTHUB_NUM_PORTS > 7) {
> > +		buf[1] = 0;
> > +		ret++;
> > +	}
> 
> Endianness bug.
> 

Could you elaborate?
It was my understanding that this buffer was host-endian.
Is this an unacceptable way to clear the buffer?

> > +
> > +	for (i = 0; i < MAUSB_ROOTHUB_NUM_PORTS; i++) {
> > +		port_change = roothub->port_status[i].wPortChange;
> > +		if (port_change)
> > +			status |= (1 << (i + 1));
> > +	}
> > +
> > +	mausb_dbg(mhcd, "%s: hub status is 0x%x\n", __func__, status);
> > +
> > +	/* hcd might be suspended, resume if there is a status change */
> > +	if (mhcd->disabled == 0) {
> > +		if ((hcd->state == HC_STATE_SUSPENDED) && status)
> > +			usb_hcd_resume_root_hub(hcd);
> > +	}
> > +
> > +	memcpy(buf, (char *)&status, ret);
> > +
> > +	return status ? ret : 0;
> > +}
> > +
> > +/**
> > + * Sets the bitfields in the hub descriptor of the 2.0 root hub. Always
> > + * returns zero.
> > + */
> > +int mausb_set_hub_descriptor(struct usb_hub_descriptor *hub_des)
> > +{
> > +	/* set the values to the default */
> > +	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
> > +	hub_des->bDescriptorType      = USB_DT_HUB;
> > +	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
> > +	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
> > +	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
> > +	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
> 
> Is that descriptor in bus or host endianness?
> 

All of the fields are little-endian. We should be using cpu_to_le16()
when setting wHubCharacteristics.

> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * Sets the bitfields in the hub descriptor of the 3.0 root hub. Always
> > + * returns zero.
> 
> Then why return anything?
> 

Good point. I will change this (and mausb_set_hub_descriptor()) to be void.

> > + */
> > +int mausb_set_ss_hub_descriptor(struct usb_hub_descriptor *hub_des)
> > +{
> > +	/* set the values to the default */
> > +	hub_des->bDescLength          = sizeof(struct usb_hub_descriptor);
> > +	hub_des->bDescriptorType      = USB_DT_SS_HUB;
> > +	hub_des->bNbrPorts            = MAUSB_ROOTHUB_NUM_PORTS;
> > +	hub_des->wHubCharacteristics  = MAUSB_ROOTHUB_CHAR;
> > +	hub_des->bPwrOn2PwrGood       = MAUSB_ROOTHUB_PWR_ON_2_PWR_GOOD;
> > +	hub_des->bHubContrCurrent     = MAUSB_ROOTHUB_CONTR_CURRENT;
> > +
> > +	/* USB3-specific parameters */
> > +	hub_des->u.ss.bHubHdrDecLat   = MAUSB_ROOTHUB_HDR_DEC_LAT;
> > +	hub_des->u.ss.wHubDelay       = MAUSB_ROOTHUB_DELAY;
> > +	hub_des->u.ss.DeviceRemovable = MAUSB_ALL_DEV_REMOVABLE;
> > +
> > +	return 0;
> > +}
> 
> 
> > +/**
> > + * Contains all the structures required to emulate a root hub. One instance
> > + * exists per root hub.
> > + */
> > +struct __attribute__((__packed__)) mausb_root_hub {
> 
> Why __packed__ ?

Doesn't need to be. I will remove.

> > +
> > +	/* hub parameters */
> > +	struct usb_hub_descriptor descriptor;
> > +	struct usb_hub_status     status;
> > +
> > +	/* port parameters*/
> > +	struct usb_port_status    port_status[MAUSB_ROOTHUB_NUM_PORTS];
> > +
> > +	/* root hub state */
> > +	enum   mausb_rh_state     rh_state;
> > +
> > +};
> 
> 	HTH
> 		Oliver
> 
> -- 
> Oliver Neukum <oneukum@suse.de>
> 

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 05/10] added media specific (MS) TCP drivers
  2014-11-04  8:48     ` Tobias Klauser
  2014-11-04 18:02       ` Greg KH
@ 2014-11-12 19:36       ` Sean O. Stalley
  1 sibling, 0 replies; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-12 19:36 UTC (permalink / raw)
  To: Tobias Klauser; +Cc: Stephanie Wallick, linux-kernel, gregkh, devel

Thank You for reviewing our code.

I believe most of the problems you pointed out in mausb_ioctl.c
were addressed in [V2 PATCH 5/10]. I am working on adding the proper
error checking to the TCP drivers.

Greg has requested that we clean up our code internally before
submitting another patchset to the mailing list. I will make sure
we fix the problems you pointed out, but it may be a while before
you see another patchset.

Thanks,
Sean

On Tue, Nov 04, 2014 at 09:48:33AM +0100, Tobias Klauser wrote:
> On 2014-11-03 at 21:42:52 +0100, Stephanie Wallick <stephanie.s.wallick@intel.com> wrote:
> > This is where we handle media specific packets and transport. The MS driver
> > interfaces with a media agnostic (MA) driver via a series of transfer pairs.
> > Transfer pairs consist of a set of functions to pass MA USB packets back
> > and forth between MA and MS drivers. There is one transfer pair per device
> > endpoint and one transfer pair for control/management traffic. When the MA
> > driver needs to send an MA USB packet, it hands the packet off to the MS
> > layer where the packet is converted into an MS form and sent via TCP over
> > the underlying ethernet or wireless medium. When the MS driver receives a
> > packet, it converts it into an MA USB packet and hands it off the the MA
> > driver for handling.
> > 
> > In addition, the MS driver provides an interface to inititate connection events.
> > Because there are no physical MA USB ports in an MA USB host, the host must be
> > notified via software when a device is connected.
> > 
> > Lastly, the MS driver contains a number of ioctl functions that are used by a
> > utility to adjust medium-related driver parameters and connect or disconnect the
> > MA USB host and device drivers.
> > 
> > Signed-off-by: Sean O. Stalley <sean.stalley@intel.com>
> > Signed-off-by: Stephanie Wallick <stephanie.s.wallick@intel.com>
> > ---
> >  drivers/staging/mausb/drivers/mausb_ioctl.c      | 373 +++++++++++++++++++
> >  drivers/staging/mausb/drivers/mausb_ioctl.h      |  99 +++++
> >  drivers/staging/mausb/drivers/mausb_msapi.c      | 110 ++++++
> >  drivers/staging/mausb/drivers/mausb_msapi.h      | 232 ++++++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp-device.c | 147 ++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp-host.c   | 144 ++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp.c        | 446 +++++++++++++++++++++++
> >  drivers/staging/mausb/drivers/mausb_tcp.h        | 129 +++++++
> >  8 files changed, 1680 insertions(+)
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_ioctl.h
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_msapi.h
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-device.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp-host.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.c
> >  create mode 100644 drivers/staging/mausb/drivers/mausb_tcp.h
> > 
> > diff --git a/drivers/staging/mausb/drivers/mausb_ioctl.c b/drivers/staging/mausb/drivers/mausb_ioctl.c
> > new file mode 100644
> > index 0000000..0c6c6bd
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_ioctl.c
> 
> [...]
> 
> > +/**
> > + * This function is used to send a message to the user, in other words, the
> > + * calling process. It basically copies the message one byte at a time.
> > + *
> > + * @msg:	The message to be sent to the user.
> > + * @buffer:	The buffer in which to put the message. This buffer was given to
> > + *	    	us to fill.
> > + */
> > +void to_user(char *msg, long unsigned int buffer)
> > +{
> > +	int length = (int)strlen(msg);
> > +	int bytes = 0;
> > +
> > +	while (length && *msg) {
> > +		put_user(*(msg++), (char *)buffer++);
> > +		length--;
> > +		bytes++;
> > +	}
> 
> Any reason not to use copy_to_user here? That way, access_ok would only
> need to be executed once for the whole range.
> 
> In any case, the return value of put_user/copy_to_user will need to be
> checked.
> 
> > +
> > +	put_user('\0', (char *)buffer + bytes);
> > +}
> 
> [...]
> 
> > +/**
> > + * This function is used to read from the device file. From the perspective of
> > + * the device, the user is reading information from us. This is one of the
> > + * entry points to this module.
> > + *
> > + * @file:	The device file. We don't use it directly, but it's passed in.
> > + * @buffer:	The buffer to put the message into.
> > + * @length:	The max length to be read.
> > + * @offset:	File offset, which we don't use but it is passed in nontheless.
> > + */
> > +static ssize_t mausb_read(struct file *file, char __user *buffer,
> > +		size_t length, loff_t *offset)
> > +{
> > +	int bytes_read = 0;
> > +
> > +	if (*message_point == 0)
> > +		return 0;
> > +	while (length && *message_point) {
> > +		put_user(*(message_point++), buffer++);
> > +		length--;
> > +		bytes_read++;
> > +	}
> 
> See comment for to_user above. Why not use copy_to_user?
> 
> > +
> > +	return bytes_read;
> > +}
> > +
> > +/**
> > + * This function is used to write to the device file. From the perspective of
> > + * the device, the user is writing information to us. This is one of the
> > + * entry points to this module.
> > + *
> > + * @file:	The device file. We don't use it directly, but it's passed in.
> > + * @buffer:	The buffer that holds the message.
> > + * @length:	The length of the message to be written.
> > + * @offset:	File offset, which we don't use but it is passed in nontheless.
> > + */
> > +static ssize_t mausb_write(struct file *file, const char __user *buffer,
> > +		size_t length, loff_t *offset)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < length && i < BUFFER; i++)
> > +		get_user(message[i], buffer + i);
> 
> copy_from_user? In any case, check the return value here as well.
> 
> > +	message_point = message;
> > +
> > +	return i;
> > +}
> > +
> > +/**
> > + * This function is used to execute ioctl commands, determined by ioctl_func.
> > + *
> > + * @file:	  The device file. We don't use it directly, but it's passed in.
> > + * @ioctl_func:	  This value determines which ioctl function will be used.
> > + * @ioctl_buffer: This buffer is used to transfer data to/from the device.
> > + */
> > +long mausb_ioctl(struct file *file, unsigned int ioctl_func,
> > +		unsigned long ioctl_buffer)
> > +{
> 
> This entire function needs return value checks for put_user/get_user.
> 
> > +	int bytes = 0;
> > +	char *msg, *ip_addr;
> > +	char chr;
> > +	int ret, value;
> > +	unsigned long int  long_ret;
> > +
> > +	switch (ioctl_func) {
> > +	case IOCTL_SET_MSG:
> > +		msg = (char *)ioctl_buffer;
> > +		get_user(chr, msg);
> > +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> > +			get_user(chr, msg);
> > +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> > +		break;
> > +	case IOCTL_GET_MSG:
> > +		bytes = mausb_read(file, (char *)ioctl_buffer, 99, 0);
> > +		put_user('\0', (char *)ioctl_buffer + bytes);
> > +		break;
> > +	case IOCTL_GET_VRSN:
> > +		to_user(DRIVER_VERSION, ioctl_buffer);
> > +		break;
> > +	case IOCTL_GET_NAME:
> > +		to_user(MAUSB_NAME, ioctl_buffer);
> > +		break;
> > +	case IOCTL_GADGET_C:
> > +		ret = gadget_connection(1);
> > +		if (ret >= 0)
> > +			to_user("g_zero connect process complete", ioctl_buffer);
> > +		else
> > +			to_user("g_zero connect process failed", ioctl_buffer);
> > +		break;
> > +	case IOCTL_GADGET_D:
> > +		ret = gadget_connection(0);
> > +		if (ret >= 0)
> > +			to_user("g_zero disconnect process complete",
> > +				ioctl_buffer);
> > +		else
> > +			to_user("g_zero disconnect process failed",
> > +				ioctl_buffer);
> > +		break;
> > +	case IOCTL_MED_DELAY:
> > +		msg = (char *)ioctl_buffer;
> > +		get_user(chr, msg);
> > +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> > +			get_user(chr, msg);
> > +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> > +		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
> > +			/* TODO: handle error */
> > +		}
> > +		ret = set_medium_delay(value);
> > +		sprintf(message_point, "DELAY VALUE: ms: %d, jiffies: %d\n",
> > +			value, ret);
> > +		to_user(message_point, ioctl_buffer);
> > +		break;
> > +	case IOCTL_SET_IP:
> > +		msg = (char *)ioctl_buffer;
> > +		get_user(chr, msg);
> > +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> > +			get_user(chr, msg);
> > +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> > +		ip_addr = kmalloc(strlen(message_point)+1, GFP_KERNEL);
> > +		if (!ip_addr) {
> > +			printk(KERN_ALERT "Memory allocation failed!\n");
> 
> No need to print an error message for memory allocation failures,
> kmalloc will take care of printing a more extensive message.
> 
> > +			break;
> > +		}
> > +		strcpy(ip_addr, message_point);
> > +		sprintf(message_point, "Connecting to ...\nIP Address: %s\n",
> > +			ip_addr);
> > +		to_user(message_point, ioctl_buffer);
> > +		kfree(ip_addr);
> > +		break;
> > +	case IOCTL_SET_PORT:
> > +		msg = (char *)ioctl_buffer;
> > +		get_user(chr, msg);
> > +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> > +			get_user(chr, msg);
> > +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> > +		if (kstrtoint((const char *)message_point, 0, &value) != 0) {
> > +			/* TODO: handle error */
> > +		}
> > +		ret = set_port_no(value);
> > +		sprintf(message_point, "PORT NUMBER:%d, Returned %i\n", value,
> > +			ret);
> > +		to_user(message_point, ioctl_buffer);
> > +		break;
> > +	case IOCTL_SET_IP_DECIMAL:
> > +		msg = (char *)ioctl_buffer;
> > +		get_user(chr, msg);
> > +		for (bytes = 0; chr && bytes < BUFFER; bytes++, msg++)
> > +			get_user(chr, msg);
> > +		mausb_write(file, (char *)ioctl_buffer, bytes, 0);
> > +		if (kstrtoul((const char *)message_point, 0, &long_ret) != 0) {
> > +			/* TODO: handle error */
> > +		}
> > +
> > +		ret = set_ip_addr(long_ret);
> > +		sprintf(message_point, "\nDecimal Value:%lx returned %i\n",
> > +			long_ret, ret);
> > +		to_user(message_point, ioctl_buffer);
> > +		break;
> > +	case IOCTL_SET_MAC:
> > +		{
> > +			u8 *mac = kmalloc(6, GFP_KERNEL);
> > +			u8 *buf = (u8 __user *)ioctl_buffer;
> > +			int i, ret;
> > +			if (!mac) {
> > +				pr_err("Memory allocation failed!\n");
> 
> See comment above. Since this is only a 6 byte buffer, it's probably
> easier to just allocate it on the stack.
> 
> > +				break;
> > +			}
> > +			ret = copy_from_user(mac, buf, 6);
> > +			if (ret) {
> > +				pr_err("copy_from_user failed\n");
> > +				kfree(mac);
> > +				break;
> > +			}
> > +			for (i = 0; i < ETH_ALEN; i++)
> > +				pr_info("mac[%d]=0x%x\n", i, mac[i]);
> > +			ret = set_mac_addr(mac);
> > +			if (ret)
> > +				pr_err("unable to set MAC addr\n");
> > +			kfree(mac);
> > +			break;
> > +		}
> > +	}
> > +
> > +	return 0;
> 
> You probably want to return an error here in case anything went wrong
> above or if the ioctl number is invalid.
> 
> > +}
> 
> [...]
> 
> > diff --git a/drivers/staging/mausb/drivers/mausb_msapi.c b/drivers/staging/mausb/drivers/mausb_msapi.c
> > new file mode 100644
> > index 0000000..9dd8fa5
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_msapi.c
> 
> [...]
> 
> > +/**
> > + * Frees the given ms_pkt and associated buffers. This function is not
> > + * necessary to use the API, but could be useful on both sides of the interface.
> > + */
> > +void mausb_free_ms_pkt(struct ms_pkt *pkt)
> > +{
> > +	int i;
> > +	void *current_buf;
> > +
> > +	for (i = 0; i < pkt->nents; ++i) {
> > +		current_buf = pkt[i].kvec->iov_base;
> > +		if (NULL != current_buf) {
> > +			kfree(current_buf);
> > +		} else {
> > +			printk(KERN_DEBUG "%s: cannot find buffer for "
> > +				"kvec #%i in ms_pkt at %p\n",
> > +				__func__, i, pkt->kvec);
> 
> pr_debug()
> 
> > +		}
> > +	}
> > +
> > +	kfree(pkt);
> > +
> > +	return;
> > +}
> > +EXPORT_SYMBOL(mausb_free_ms_pkt);
> > +
> > +/**
> > + * Calculates the total length of the data in a ms_pkt. Returns the total
> > + * length of the data in the ms_pkt, or a negative errno.
> > + */
> > +int mausb_ms_pkt_length(struct ms_pkt *pkt)
> > +{
> > +	int i;
> > +	int total_length = 0;
> > +
> > +	for (i = 0; i < pkt->nents; ++i)
> > +		total_length += pkt[i].kvec->iov_len;
> > +
> > +	printk(KERN_DEBUG "%s: total *kvec length: %i\n", __func__,
> > +		total_length);
> 
> pr_debug()
> 
> > +
> > +	return total_length;
> > +}
> 
> [...]
> 
> > diff --git a/drivers/staging/mausb/drivers/mausb_tcp-device.c b/drivers/staging/mausb/drivers/mausb_tcp-device.c
> > new file mode 100644
> > index 0000000..28978a0
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_tcp-device.c
> 
> [...]
> 
> > +static int mausb_tcp_device_connect(int on)
> > +{
> > +	int ret;
> > +
> > +	if (on && dev_tcp_medium->socket == NULL) {
> > +		ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
> > +			&dev_tcp_medium->socket);
> > +
> > +		if (0 > ret) /* TODO: real errorchecking */
> > +			return ret;
> > +
> > +		do {
> > +			ret = kernel_connect(dev_tcp_medium->socket,
> > +				&dev_tcp_medium->addr,
> > +				sizeof(dev_tcp_medium->addr_in), O_RDWR);
> > +			printk(KERN_DEBUG "%s:kernel_connect returned %i\n",
> > +				__func__, ret);
> 
> pr_debug(), here any in several other places across the file...
> 
> > +
> > +			if (0 > ret) {
> > +				/* poll until we can connect sucessfully */
> > +				msleep(MAUSB_TCP_DEV_CONNECT_POLL_MS);
> > +			}
> > +
> > +
> > +		} while (0 > ret);
> > +
> > +		/*spawn off a listening thread */
> > +		dev_tcp_medium->recv_task = kthread_run(mausb_tcp_device_thread,
> > +			NULL, "mausb_tcp_device_thread");
> 
> kthread_run might return an ERR_PTR which needs to be handled here.
> 
> > +	}
> > +
> > +	ret = dev_tcp_medium->ma_driver->device_connect(on);
> > +
> > +	return ret;
> > +}
> 
> [...]
> 
> > diff --git a/drivers/staging/mausb/drivers/mausb_tcp-host.c b/drivers/staging/mausb/drivers/mausb_tcp-host.c
> > new file mode 100644
> > index 0000000..0302031
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_tcp-host.c
> 
> [...]
> 
> > +static int mausb_tcp_host_connect(int on)
> > +{
> > +	int ret;
> > +
> > +	if (on) {
> > +		ret = kernel_bind(host_tcp_medium->setup_socket,
> > +			&host_tcp_medium->addr,
> > +			sizeof(host_tcp_medium->addr_in));
> 
> Missing error handling.
> 
> > +
> > +		ret = kernel_listen(host_tcp_medium->setup_socket,
> > +			MAUSB_TCP_MAX_NUM_CHANNELS);
> 
> Missing error handling.
> 
> > +		printk(KERN_DEBUG "%s: kernel_listen returned %i\n",
> > +			__func__, ret);
> > +
> > +		ret = kernel_accept(host_tcp_medium->setup_socket,
> > +				    &host_tcp_medium->socket, 0);
> > +		printk(KERN_DEBUG "%s:kernel_accept returned %i\n",
> > +			__func__, ret);
> > +
> > +		if (0 > ret)
> > +			return ret;
> 
> kernel_accept might return negative values in case of an error, which
> needs to be handled properly here.
> 
> > +
> > +		if (NULL == host_tcp_medium->recv_task) {
> > +			host_tcp_medium->recv_task = kthread_run(
> > +				mausb_tcp_host_thread, NULL,
> > +				"mausb_tcp_host_thread");
> > +		}
> > +	}
> > +
> > +	ret = host_tcp_medium->ma_driver->device_connect(on);
> > +
> > +	return ret;
> > +}
> 
> [...]
> 
> > diff --git a/drivers/staging/mausb/drivers/mausb_tcp.c b/drivers/staging/mausb/drivers/mausb_tcp.c
> > new file mode 100644
> > index 0000000..291139e
> > --- /dev/null
> > +++ b/drivers/staging/mausb/drivers/mausb_tcp.c
> 
> [...]
> 
> > +int mausb_tcp_receive_loop(struct mausb_tcp_medium *tcp_medium)
> > +{
> > +	struct msghdr msg;
> > +	struct ms_pkt *pkt;
> > +	int data_rcvd = 0;
> > +
> > +	mausb_tcp_init_msg(&msg);
> > +
> > +	while (!kthread_should_stop()) {
> > +
> > +		pkt = kzalloc(sizeof(struct ms_pkt), GFP_KERNEL);
> 
> Missing return value check.
> 
> > +
> > +		printk(KERN_DEBUG "%s: preparing to receive data\n",
> > +			__func__);
> > +
> > +		data_rcvd = mausb_tcp_receive_packet(tcp_medium, &msg, pkt);
> > +
> > +		if (0 >= data_rcvd) {
> > +			printk(KERN_DEBUG "%s: received no data (err %i)\n",
> > +				__func__, data_rcvd);
> > +
> > +			sock_release(tcp_medium->socket);
> > +			return data_rcvd;
> > +
> > +		} else {
> > +			printk(KERN_DEBUG "%s: received %i bytes\n",
> > +				__func__, data_rcvd);
> > +		}
> > +
> > +		if (data_rcvd > 0) {
> > +			mausb_transfer_packet(pkt,
> > +				&tcp_medium->ma_driver->pkt_dmux);
> > +		}
> > +
> > +		data_rcvd = 0;
> > +	}
> > +
> > +	sock_release(tcp_medium->socket);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(mausb_tcp_receive_loop);
> 
> [...]
> 
> > +/**
> > + * initialization function
> > + */
> > +struct mausb_tcp_medium *alloc_init_mausb_tcp_medium(
> > +	enum mausb_tcp_module_type type)
> > +{
> > +	struct mausb_tcp_medium *medium;
> > +	int ret;
> > +
> > +	printk(KERN_DEBUG "%s\n", __func__);
> > +
> > +	medium = kzalloc(sizeof(struct mausb_tcp_medium), GFP_KERNEL);
> > +	if (NULL == medium) {
> > +		printk(KERN_DEBUG "%s: memory allocation failed\n", __func__);
> 
> No error message needed, kmalloc will take care of it.
> 
> > +		return NULL;
> > +	}
> > +
> > +	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
> > +		&medium->setup_socket);
> 
> Error handling is missing.
> 
> > +
> > +	medium->addr_in.sin_family = AF_INET;
> > +	medium->addr_in.sin_port = htons(MAUSB_TCP_PORT_HOST);
> > +
> > +	spin_lock_init(&medium->lock);
> > +
> > +	tcp_medium[type] = medium;
> > +
> > +	return medium;
> > +}
> > +EXPORT_SYMBOL(alloc_init_mausb_tcp_medium);

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs
  2014-11-12 19:28       ` Sean O. Stalley
@ 2014-11-12 19:52         ` Alan Stern
  0 siblings, 0 replies; 54+ messages in thread
From: Alan Stern @ 2014-11-12 19:52 UTC (permalink / raw)
  To: Sean O. Stalley
  Cc: Oliver Neukum, Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

On Wed, 12 Nov 2014, Sean O. Stalley wrote:

> > > --- /dev/null
> > > +++ b/drivers/staging/mausb/drivers/mausb_hub.c
> > 
> > > +/**
> > > + * Returns true if the given is the superspeed HCD. Note: The primary HCD is
> > > + * High Speed and the shared HCD is SuperSpeed.
> > > + */
> > 
> > Why in that order?
> > 
> 
> We should probably switch this & make the superspeed hub primary.
> That way we match the xhci driver.

xhci-hcd makes the high-speed hcd the primary one.  This is because it 
registers the high-speed hcd before the SuperSpeed hcd.  There was a 
good reason for doing it this way, but I can't remember what it was 
(it's buried somewhere in the email archives).

That's why when you look at the output from lsusb or something similar,
a SuperSpeed root hub has a bus number that is one higher than its peer
high-speed root hub.

> > > +int mausb_hub_status_data(struct usb_hcd *hcd, char *buf)
> > > +{
> > > +	int                      i;
> > > +	u16                      port_change = 0;
> > > +	u32                      status = 0;
> > > +	int                      ret = 1;
> > > +	struct mausb_hcd	 *mhcd = usb_hcd_to_mausb_hcd(hcd);
> > > +	struct mausb_root_hub	 *roothub = usb_hcd_to_roothub(hcd);
> > > +
> > > +	/*
> > > +	 * Buf should never be more that 2 bytes. USB 3.0 hubs cannot have
> > > +	 * more than 15 downstream ports.
> > > +	 */
> > > +	buf[0] = 0;
> > > +	if (MAUSB_ROOTHUB_NUM_PORTS > 7) {
> > > +		buf[1] = 0;
> > > +		ret++;
> > > +	}
> > 
> > Endianness bug.
> > 
> 
> Could you elaborate?
> It was my understanding that this buffer was host-endian.
> Is this an unacceptable way to clear the buffer?

I don't understand Oliver's objection here.  The buffer is 
little-endian, just as it is for real hubs.  The code seems correct.

Alan Stern


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-11 15:54   ` Alan Stern
@ 2014-11-12 21:40     ` Sean O. Stalley
  2014-11-12 22:03       ` Alan Stern
  2014-11-12 22:58       ` Sean O. Stalley
  0 siblings, 2 replies; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-12 21:40 UTC (permalink / raw)
  To: Alan Stern; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

Thanks for reviewing. My responses are inline.

Greg has asked that we clean up this code internally before we
send out another patchset to the mailing list. I will address
the issues you pointed out, but it may be a while before you see
another patchset.

Thanks Again,
Sean

On Tue, Nov 11, 2014 at 10:54:30AM -0500, Alan Stern wrote:
> On Mon, 10 Nov 2014, Stephanie Wallick wrote:
> 
> > +static struct mausb_hcd mhcd;
> 
> Only one statically-allocated structure?  What if somebody wants to 
> have more than one of these things in their system?
> 

Our plan to support multiple MA devices is to have them all connected
to the same virtual host controller, so only 1 would be needed.

Would you prefer we have 1 host controller instance per MA device?
We are definitely open to suggestions on how this should be architected.

> > +/**
> > + * @maurb:	Media agnostic structure with URB to release.
> > + * @status:	Status for URB that is getting released.
> > + *
> > + * Removes an URB from the queue, deletes the media agnostic information in
> > + * the urb, and gives the URB back to the HCD. Caller must be holding the
> > + * driver's spinlock.
> > + */
> > +void mausb_unlink_giveback_urb(struct mausb_urb *maurb, int status)
> > +{
> > +	struct urb		*urb;
> > +	struct usb_hcd		*hcd;
> > +	struct api_context	*ctx = NULL;
> > +	unsigned long		irq_flags;
> > +
> > +	hcd = mausb_hcd_to_usb_hcd(&mhcd);
> > +
> > +	spin_lock_irqsave(&mhcd.giveback_lock, irq_flags);
> 
> Why do you need multiple spinlocks?  Isn't one lock sufficient?
> 
We will simplify the locking scheme before resubmitting.

I think it might be worthwhile to have a per-endpoint lock, see below.

> > +	if (!maurb) {
> > +		mausb_err(&mhcd, "%s: no maurb\n", __func__);
> > +		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> > +		return;
> > +	} else {
> > +		urb = maurb->urb;
> > +		ctx = urb->context;
> > +	}
> > +
> > +	if (!urb) {
> > +		mausb_err(&mhcd, "%s: no urb\n", __func__);
> > +		mausb_internal_drop_maurb(maurb, &mhcd);
> > +		spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> > +		return;
> > +	}
> > +
> > +	mausb_dbg(&mhcd, "%s: returning urb with status %i\n", __func__, status);
> > +
> > +	usb_hcd_unlink_urb_from_ep(hcd, urb);
> > +	usb_hcd_giveback_urb(hcd, urb, status);
> 
> You must not call this function while holding any spinlocks.  What happens
> if the URB's completion routine tries to resubmit?
> 

This works with our multi-lock scheme, but I will fix when we move to 1 lock.

> > +
> > +	/* remove the mausb-specific data */
> > +	mausb_internal_drop_maurb(maurb, &mhcd);
> > +
> > +	spin_unlock_irqrestore(&mhcd.giveback_lock, irq_flags);
> > +}
> > +
> > +/**
> > + * Adds an URB to the endpoint queue then calls the URB handler. URB is wrapped
> > + * in media agnostic structure before being enqueued.
> > + */
> > +static int mausb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
> > +		gfp_t memflags)
> > +{
> > +	int			ret = 0;
> > +	struct mausb_urb	*maurb;
> > +	struct mausb_host_ep	*ep;
> > +	unsigned long		irq_flags;
> > +
> > +	if (!hcd || !urb) {
> > +		pr_err("%s: no %s\n", __func__, (hcd ? "urb" : "USB hcd"));
> > +	}
> 
> This can never happen.  The USB core guarantees it; you don't need 
> to check.
> 

I will remove this check (along with any other unnecessary checks for things
guaranteed from usbcore).

> > +	ep   = usb_to_ma_endpoint(urb->ep);
> > +
> > +	if (!ep) {
> > +		mausb_err(&mhcd, "%s: no endpoint\n", __func__);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (urb->status != -EINPROGRESS) {
> > +		mausb_err(&mhcd, "%s: urb already unlinked, status is %i\n",
> > +			__func__, urb->status);
> > +		return urb->status;
> > +	}
> 
> You also don't need to check this.
> 
Will remove.

> > +	/* If the endpoint isn't activated, we can't enqueue anything. */
> > +	if (MAUSB_EP_HANDLE_UNASSIGNED == ep->ep_handle_state) {
> > +		mausb_err(&mhcd, "%s: endpoint handle unassigned\n", __func__);
> > +		return -EPIPE;
> > +	}
> > +
> > +	if (USB_SPEED_FULL != urb->dev->speed) /* suppress checks */
> > +		ep->max_pkt = usb_endpoint_maxp(&urb->ep->desc);
> 
> What happens to full-speed devices?  Don't they have maxpacket values?
> 
> > +
> > +	/* initialize the maurb */
> > +	maurb = mausb_alloc_maurb(ep, memflags);
> > +	if (!maurb) {
> > +		mausb_err(&mhcd, "could not allocate memory for MA USB urb\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	/* set maurb member values */
> > +	maurb->urb = urb;
> > +	urb->hcpriv = maurb;
> > +
> > +	/* submit urb to hcd and add to endpoint queue */
> > +	ret = usb_hcd_link_urb_to_ep(hcd, urb);
> 
> Read the kerneldoc for this function.  You must hold your private
> spinlock when you call it.
> 

Will fix this & make sure we hold our lock.

> > +	if (ret < 0) {
> > +		mausb_err(&mhcd, "urb enqueue failed: error %d\n", ret);
> > +		usb_hcd_unlink_urb_from_ep(hcd, urb);
> > +		return ret;
> > +	}
> > +
> > +	/* get usb device and increment reference counter */
> > +	if (!mhcd.udev) {
> > +		mhcd.udev = urb->dev;
> > +		usb_get_dev(mhcd.udev);
> > +	}
> 
> What happens if more than one device is in use at a time?
> 
> > +
> > +	/* add urb to queue list */
> > +	spin_lock_irqsave(&ep->ep_lock, irq_flags);
> > +	list_add_tail(&maurb->urb_list, &ep->urb_list);
> > +	spin_unlock_irqrestore(&ep->ep_lock, irq_flags);
> 
> Yet another class of spinlocks!
> 

If we get rid of these locks, endpoints can't run simultaneously.
MA USB IN endpoints have to copy data, which could take a while.

Couldn't this cause a bottleneck?

> > +	/* add urb to ma hcd urb list */
> > +	spin_lock_irqsave(&mhcd.urb_list_lock, irq_flags);
> 
> And another!  You really shouldn't need more than one lock.
> 

Will remove.

> > +	list_add_tail(&maurb->ma_hcd_urb_list, &mhcd.enqueue_urb_list);
> > +	spin_unlock_irqrestore(&mhcd.urb_list_lock, irq_flags);
> > +
> > +	/* send to MA transfer process */
> > +	wake_up(&mhcd.waitq);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * Dequeues an URB.
> > + */
> > +static int mausb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
> > +{
> > +	int			ret	= 0;
> > +	struct mausb_host_ep	*ep = usb_to_ma_endpoint(urb->ep);
> > +	struct mausb_urb	*maurb = usb_urb_to_mausb_urb(urb);
> > +	unsigned long		irq_flags;
> > +
> > +	/* For debugging - we want to know who initiated URB dequeue. */
> > +	dump_stack();
> 
> Debugging things like this should be removed before a patch is submitted.

Will grep & remove all debugging messages before we release the next patchset.

> 
> That's enough for now.  Obviously there are a lot of issues in this 
> driver which need to be fixed up.

We will try to address all the obvious issues before submitting again.

> 
> Alan Stern
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-12 21:40     ` Sean O. Stalley
@ 2014-11-12 22:03       ` Alan Stern
  2014-11-14 22:48         ` Sean O. Stalley
  2014-11-12 22:58       ` Sean O. Stalley
  1 sibling, 1 reply; 54+ messages in thread
From: Alan Stern @ 2014-11-12 22:03 UTC (permalink / raw)
  To: Sean O. Stalley; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

On Wed, 12 Nov 2014, Sean O. Stalley wrote:

> On Tue, Nov 11, 2014 at 10:54:30AM -0500, Alan Stern wrote:
> > On Mon, 10 Nov 2014, Stephanie Wallick wrote:
> > 
> > > +static struct mausb_hcd mhcd;
> > 
> > Only one statically-allocated structure?  What if somebody wants to 
> > have more than one of these things in their system?
> > 
> 
> Our plan to support multiple MA devices is to have them all connected
> to the same virtual host controller, so only 1 would be needed.
> 
> Would you prefer we have 1 host controller instance per MA device?
> We are definitely open to suggestions on how this should be architected.

I haven't read the MA USB spec, so I don't know how it's intended to 
work.  Still, what happens if you create a virtual host controller 
with, say, 16 ports, and then someone wants to connect a 17th MA 
device?

Also, I noticed that your patch adds a new bus type for these MA host 
controllers.  It really seems like overkill to have a whole new bus 
type if there's only going to be one device on it.

> If we get rid of these locks, endpoints can't run simultaneously.
> MA USB IN endpoints have to copy data, which could take a while.

I don't know what you mean by "run simultaneously".  Certainly multiple 
network packets can be transmitted and received concurrently even if 
you use a single spinlock, since your locking won't affect the 
networking subsystem.

> Couldn't this cause a bottleneck?

Probably not enough to matter.  After all, the other host controller
drivers rely on a single spinlock.  And if it did matter, you could
drop the spinlock while copying the data.

Alan Stern


^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-12 21:40     ` Sean O. Stalley
  2014-11-12 22:03       ` Alan Stern
@ 2014-11-12 22:58       ` Sean O. Stalley
  1 sibling, 0 replies; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-12 22:58 UTC (permalink / raw)
  To: Alan Stern; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

Sorry, for got to respond to a couple comments. See responses below.

On Wed, Nov 12, 2014 at 01:40:21PM -0800, Sean O. Stalley wrote:
> Thanks for reviewing. My responses are inline.
> 
> Greg has asked that we clean up this code internally before we
> send out another patchset to the mailing list. I will address
> the issues you pointed out, but it may be a while before you see
> another patchset.
> 
> Thanks Again,
> Sean
> 
> On Tue, Nov 11, 2014 at 10:54:30AM -0500, Alan Stern wrote:
> > On Mon, 10 Nov 2014, Stephanie Wallick wrote:
> > > +	/* If the endpoint isn't activated, we can't enqueue anything. */
> > > +	if (MAUSB_EP_HANDLE_UNASSIGNED == ep->ep_handle_state) {
> > > +		mausb_err(&mhcd, "%s: endpoint handle unassigned\n", __func__);
> > > +		return -EPIPE;
> > > +	}
> > > +
> > > +	if (USB_SPEED_FULL != urb->dev->speed) /* suppress checks */
> > > +		ep->max_pkt = usb_endpoint_maxp(&urb->ep->desc);
> > 
> > What happens to full-speed devices?  Don't they have maxpacket values?
> > 

This was part of a work-around.
Per the MA spec (section 7.3.2.2), wMaxPacketSize should be initially
set to 8 for EP0 of FS devices. The usbcore sets it to 64.

This makes sure the EPHandleReq Packet has the per-spec values.

> > > +	if (ret < 0) {
> > > +		mausb_err(&mhcd, "urb enqueue failed: error %d\n", ret);
> > > +		usb_hcd_unlink_urb_from_ep(hcd, urb);
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* get usb device and increment reference counter */
> > > +	if (!mhcd.udev) {
> > > +		mhcd.udev = urb->dev;
> > > +		usb_get_dev(mhcd.udev);
> > > +	}
> > 
> > What happens if more than one device is in use at a time?
> > 

This is wrong. This call should be in mausb_internal_alloc_dev(). Will fix.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-12 22:03       ` Alan Stern
@ 2014-11-14 22:48         ` Sean O. Stalley
  2014-11-15 21:29           ` Alan Stern
  0 siblings, 1 reply; 54+ messages in thread
From: Sean O. Stalley @ 2014-11-14 22:48 UTC (permalink / raw)
  To: Alan Stern; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

On Wed, Nov 12, 2014 at 05:03:18PM -0500, Alan Stern wrote:
> On Wed, 12 Nov 2014, Sean O. Stalley wrote:
> > Our plan to support multiple MA devices is to have them all connected
> > to the same virtual host controller, so only 1 would be needed.
> > 
> > Would you prefer we have 1 host controller instance per MA device?
> > We are definitely open to suggestions on how this should be architected.
> 
> I haven't read the MA USB spec, so I don't know how it's intended to 
> work.  Still, what happens if you create a virtual host controller 
> with, say, 16 ports, and then someone wants to connect a 17th MA 
> device?

To summarize the spec:
MA USB groups a host & connected devices into MA service sets (MSS).
The architectural limit is 254 MA devices per MSS.

If the host needs to connect more devices than that, It can start a
new MSS and connect to 254 more MA devices.



Is supporting up to 254 devices on one machine sufficient?

Would it make sense (and does the usb stack support) having 254 root
ports on one host controller? If so, we could make our host
controller instance have 254 ports. I'm guessing the hub driver may have
a problem with this (especially for superspeed).

If that doesn't make sense (or isn't supported), we can have 1 host
controller instance per MA device. Would that be preferred?

> Also, I noticed that your patch adds a new bus type for these MA host 
> controllers.  It really seems like overkill to have a whole new bus 
> type if there's only going to be one device on it.

The bus was added when we were quickly trying to replace the platform
device code. It's probably not the right thing to do.

I'm still not sure why we can't make our hcd a platform device,
especially since dummy_hcd & the usbip's hcd are both platform devices.

> > If we get rid of these locks, endpoints can't run simultaneously.
> > MA USB IN endpoints have to copy data, which could take a while.
> 
> I don't know what you mean by "run simultaneously".  Certainly multiple 
> network packets can be transmitted and received concurrently even if 
> you use a single spinlock, since your locking won't affect the 
> networking subsystem.

I meant we couldn't have 2 threads in our driver. With one lock,
One thread would always have to wait for the other, even though
they could be working on 2 different endpoints doing completely
independent tasks.

> > Couldn't this cause a bottleneck?
> 
> Probably not enough to matter.  After all, the other host controller
> drivers rely on a single spinlock.  And if it did matter, you could
> drop the spinlock while copying the data.

Good point. We can cut our driver down to using 1 lock. If we find that
only having 1 spinlock does cause a bottleneck, we can deal with it then.


Thanks,
Sean

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver
  2014-11-14 22:48         ` Sean O. Stalley
@ 2014-11-15 21:29           ` Alan Stern
  0 siblings, 0 replies; 54+ messages in thread
From: Alan Stern @ 2014-11-15 21:29 UTC (permalink / raw)
  To: Sean O. Stalley; +Cc: Stephanie Wallick, linux-kernel, gregkh, linux-usb, devel

On Fri, 14 Nov 2014, Sean O. Stalley wrote:

> To summarize the spec:
> MA USB groups a host & connected devices into MA service sets (MSS).
> The architectural limit is 254 MA devices per MSS.
> 
> If the host needs to connect more devices than that, It can start a
> new MSS and connect to 254 more MA devices.
> 
> 
> 
> Is supporting up to 254 devices on one machine sufficient?

It's probably more than enough.

> Would it make sense (and does the usb stack support) having 254 root
> ports on one host controller? If so, we could make our host
> controller instance have 254 ports. I'm guessing the hub driver may have
> a problem with this (especially for superspeed).

The USB stack is likely to have problems if there are more than 31 
ports on any hub.

> If that doesn't make sense (or isn't supported), we can have 1 host
> controller instance per MA device. Would that be preferred?

It doesn't make much difference.  Whatever you think will be easier to 
support.  You might check and see how usbip does it.

> > Also, I noticed that your patch adds a new bus type for these MA host 
> > controllers.  It really seems like overkill to have a whole new bus 
> > type if there's only going to be one device on it.
> 
> The bus was added when we were quickly trying to replace the platform
> device code. It's probably not the right thing to do.
> 
> I'm still not sure why we can't make our hcd a platform device,
> especially since dummy_hcd & the usbip's hcd are both platform devices.

A platform device is the right way to go.

Alan Stern


^ permalink raw reply	[flat|nested] 54+ messages in thread

end of thread, other threads:[~2014-11-15 21:29 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <MA USB drivers>
2014-11-03 20:42 ` [PATCH 00/10] MA USB drivers cover letter Stephanie Wallick
2014-11-03 20:42   ` [PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
2014-11-03 21:18     ` Greg KH
2014-11-03 23:47       ` steph
2014-11-03 21:21     ` Greg KH
2014-11-04  0:04       ` steph
2014-11-04  0:13         ` Greg KH
2014-11-04  0:59           ` steph
2014-11-05 20:14           ` sostalle
2014-11-05 22:08             ` Greg KH
2014-11-03 20:42   ` [PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
2014-11-03 20:42   ` [PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
2014-11-03 20:42   ` [PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
2014-11-03 20:42   ` [PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
2014-11-04  8:48     ` Tobias Klauser
2014-11-04 18:02       ` Greg KH
2014-11-12 19:36       ` Sean O. Stalley
2014-11-03 20:42   ` [PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
2014-11-03 20:42   ` [PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
2014-11-03 20:42   ` [PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
2014-11-03 20:42   ` [PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
2014-11-03 20:42   ` [PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
2014-11-03 21:22     ` Greg KH
2014-11-03 21:24     ` Greg KH
     [not found]       ` <54591319.c3b5440a.7374.5f85SMTPIN_ADDED_BROKEN@mx.google.com>
2014-11-04 18:02         ` Greg KH
2014-11-04  9:00   ` [PATCH 00/10] MA USB drivers cover letter Bjørn Mork
2014-11-05  1:31     ` sostalle
2014-11-11  2:09 ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Stephanie Wallick
2014-11-11  2:09   ` [V2 PATCH 02/10] added media agnostic (MA) USB HCD roothubs Stephanie Wallick
2014-11-12  8:35     ` Oliver Neukum
2014-11-12 19:28       ` Sean O. Stalley
2014-11-12 19:52         ` Alan Stern
2014-11-11  2:09   ` [V2 PATCH 03/10] added media agnostic (MA) data structures and handling Stephanie Wallick
2014-11-11  4:38     ` Greg KH
2014-11-11 22:42       ` Sean O. Stalley
2014-11-12  1:14         ` Greg KH
2014-11-12  2:01           ` steph
2014-11-11  2:09   ` [V2 PATCH 04/10] added media agnostic (MA) USB packet handling Stephanie Wallick
2014-11-12 14:01     ` Oliver Neukum
2014-11-11  2:09   ` [V2 PATCH 05/10] added media specific (MS) TCP drivers Stephanie Wallick
2014-11-11  4:21     ` Greg KH
2014-11-11  2:09   ` [V2 PATCH 06/10] added media agnostic (MA) UDC Stephanie Wallick
2014-11-11  2:09   ` [V2 PATCH 07/10] added media agnostic (MA) USB management packet handling Stephanie Wallick
2014-11-11  2:09   ` [V2 PATCH 08/10] added media agnostic (MA) USB data " Stephanie Wallick
2014-11-11  2:09   ` [V2 PATCH 09/10] added tools for building/loading media agnostic (MA) USB drivers Stephanie Wallick
2014-11-11  2:09   ` [V2 PATCH 10/10] added kernel build, configuration, and TODO files Stephanie Wallick
2014-11-11  4:23     ` Greg KH
2014-11-11  4:08   ` [V2 PATCH 01/10] added media agnostic (MA) USB HCD driver Greg KH
2014-11-11 15:54   ` Alan Stern
2014-11-12 21:40     ` Sean O. Stalley
2014-11-12 22:03       ` Alan Stern
2014-11-14 22:48         ` Sean O. Stalley
2014-11-15 21:29           ` Alan Stern
2014-11-12 22:58       ` Sean O. Stalley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).