lkml.org 
[lkml]   [2014]   [Nov]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[V2 PATCH 03/10] added media agnostic (MA) data structures and handling
Date
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


\
 
 \ /
  Last update: 2014-11-11 03:41    [W:0.238 / U:2.532 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site