[PATCH 03/10] added media agnostic (MA) data structures and handling
From: Stephanie Wallick
Date: Mon Nov 03 2014 - 15:51:56 EST
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@xxxxxxxxx>
Signed-off-by: Stephanie Wallick <stephanie.s.wallick@xxxxxxxxx>
---
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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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@xxxxxxxxx
+ * Stephanie Wallick, stephanie.s.wallick@xxxxxxxxx
+ * 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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/