staging: octeon-usb: use list_for_each_entry_safe()
[deliverable/linux.git] / drivers / staging / octeon-usb / octeon-hcd.c
index fa23889cc9a5781cb23061fd5d3514c885eeffed..8e0fcbd173f219ced4bbf0390e131cdc691a0173 100644 (file)
@@ -66,8 +66,7 @@
 #include <asm/octeon/cvmx-sysinfo.h>
 #include <asm/octeon/cvmx-helper-board.h>
 
-#include "cvmx-usbcx-defs.h"
-#include "cvmx-usbnx-defs.h"
+#include "octeon-hcd.h"
 
 /**
  * enum cvmx_usb_speed - the possible USB device speeds
@@ -204,55 +203,6 @@ struct cvmx_usb_iso_packet {
        enum cvmx_usb_complete status;
 };
 
-/**
- * enum cvmx_usb_callback - possible callback reasons for the USB API
- *
- * @CVMX_USB_CALLBACK_TRANSFER_COMPLETE: A callback of this type is called when
- *                                      a submitted transfer completes. The
- *                                      completion callback will be called even
- *                                      if the transfer fails or is canceled.
- *                                      The status parameter will contain
- *                                      details of why he callback was called.
- * @CVMX_USB_CALLBACK_PORT_CHANGED:     The status of the port changed. For
- *                                      example, someone may have plugged a
- *                                      device in. The status parameter
- *                                      contains CVMX_USB_COMPLETE_SUCCESS. Use
- *                                      cvmx_usb_get_status() to get the new
- *                                      port status.
- * @__CVMX_USB_CALLBACK_END:            Do not use. Used internally for array
- *                                      bounds.
- */
-enum cvmx_usb_callback {
-       CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
-       CVMX_USB_CALLBACK_PORT_CHANGED,
-       __CVMX_USB_CALLBACK_END
-};
-
-struct cvmx_usb_state;
-
-/**
- * USB callback functions are always of the following type.
- * The parameters are as follows:
- *      - usb = USB device state populated by cvmx_usb_initialize().
- *      - reason = The enum cvmx_usb_callback used to register
- *        the callback.
- *      - status = The enum cvmx_usb_complete representing the
- *        status code of a transaction.
- *      - pipe_handle = The Pipe that caused this callback, or
- *        -1 if this callback wasn't associated with a pipe.
- *      - submit_handle = Transfer submit handle causing this
- *        callback, or -1 if this callback wasn't associated
- *        with a transfer.
- *      - Actual number of bytes transfer.
- *      - user_data = The user pointer supplied to the
- *        function cvmx_usb_submit() or
- *        cvmx_usb_register_callback() */
-typedef void (*cvmx_usb_callback_func_t)(struct cvmx_usb_state *usb,
-                                         enum cvmx_usb_callback reason,
-                                         enum cvmx_usb_complete status,
-                                         int pipe_handle, int submit_handle,
-                                         int bytes_transferred, void *user_data);
-
 /**
  * enum cvmx_usb_initialize_flags - flags used by the initialization function
  *
@@ -284,8 +234,6 @@ enum cvmx_usb_initialize_flags {
 /**
  * enum cvmx_usb_pipe_flags - internal flags for a pipe.
  *
- * @__CVMX_USB_PIPE_FLAGS_OPEN:             Used internally to determine if a pipe is
- *                                  open. Do not use.
  * @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
  *                                  actively using hardware. Do not use.
  * @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high
@@ -293,7 +241,6 @@ enum cvmx_usb_initialize_flags {
  *                                  use.
  */
 enum cvmx_usb_pipe_flags {
-       __CVMX_USB_PIPE_FLAGS_OPEN      = 1 << 16,
        __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17,
        __CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18,
 };
@@ -304,12 +251,6 @@ enum cvmx_usb_pipe_flags {
 /* Maximum number of times to retry failed transactions */
 #define MAX_RETRIES            3
 
-/* Maximum number of pipes that can be open at once */
-#define MAX_PIPES              32
-
-/* Maximum number of outstanding transactions across all pipes */
-#define MAX_TRANSACTIONS       256
-
 /* Maximum number of hardware channels supported by the USB block */
 #define MAX_CHANNELS           8
 
@@ -334,10 +275,6 @@ enum cvmx_usb_pipe_flags {
  */
 #define MAX_TRANSFER_PACKETS   ((1<<10)-1)
 
-enum cvmx_usb_transaction_flags {
-       __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
-};
-
 enum {
        USB_CLOCK_TYPE_REF_12,
        USB_CLOCK_TYPE_REF_24,
@@ -383,14 +320,12 @@ enum cvmx_usb_stage {
  * @iso_packets:       For ISO transactions, the sub packets in the request.
  * @actual_bytes:      Actual bytes transfer for this transaction.
  * @stage:             For control transactions, the current stage.
- * @callback:          User's callback function when complete.
- * @callback_data:     User's data.
+ * @urb:               URB.
  */
 struct cvmx_usb_transaction {
        struct cvmx_usb_transaction *prev;
        struct cvmx_usb_transaction *next;
        enum cvmx_usb_transfer type;
-       enum cvmx_usb_transaction_flags flags;
        uint64_t buffer;
        int buffer_length;
        uint64_t control_header;
@@ -402,8 +337,7 @@ struct cvmx_usb_transaction {
        int retries;
        int actual_bytes;
        enum cvmx_usb_stage stage;
-       cvmx_usb_callback_func_t callback;
-       void *callback_data;
+       struct urb *urb;
 };
 
 /**
@@ -486,15 +420,9 @@ struct cvmx_usb_tx_fifo {
  * usbcx_hprt:            Stored port status so we don't need to read a CSR to
  *                        determine splits.
  * pipe_for_channel:      Map channels to pipes.
- * free_transaction_head:  List of free transactions head.
- * free_transaction_tail:  List of free transactions tail.
  * pipe:                  Storage for pipes.
- * transaction:                   Storage for transactions.
- * callback:              User global callbacks.
- * callback_data:         User data for each callback.
  * indent:                Used by debug output to indent functions.
  * port_status:                   Last port status used for change notification.
- * free_pipes:            List of all pipes that are currently closed.
  * idle_pipes:            List of open pipes that have no transactions.
  * active_pipes:          Active pipes indexed by transfer type.
  * frame_number:          Increments every SOF interrupt for time keeping.
@@ -506,15 +434,8 @@ struct cvmx_usb_state {
        int idle_hardware_channels;
        union cvmx_usbcx_hprt usbcx_hprt;
        struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
-       struct cvmx_usb_transaction *free_transaction_head;
-       struct cvmx_usb_transaction *free_transaction_tail;
-       struct cvmx_usb_pipe pipe[MAX_PIPES];
-       struct cvmx_usb_transaction transaction[MAX_TRANSACTIONS];
-       cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END];
-       void *callback_data[__CVMX_USB_CALLBACK_END];
        int indent;
        struct cvmx_usb_port_status port_status;
-       struct cvmx_usb_pipe_list free_pipes;
        struct cvmx_usb_pipe_list idle_pipes;
        struct cvmx_usb_pipe_list active_pipes[4];
        uint64_t frame_number;
@@ -657,7 +578,8 @@ static inline void __cvmx_usb_write_csr64(struct cvmx_usb_state *usb,
 static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_state *usb,
                                              struct cvmx_usb_pipe *pipe)
 {
-       return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
+       return pipe->device_speed != CVMX_USB_SPEED_HIGH &&
+              usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH;
 }
 
 
@@ -707,54 +629,6 @@ static int cvmx_usb_get_num_ports(void)
        return arch_ports;
 }
 
-
-/**
- * Allocate a usb transaction for use
- *
- * @usb:        USB device state populated by
- *              cvmx_usb_initialize().
- *
- * Returns: Transaction or NULL
- */
-static inline struct cvmx_usb_transaction *__cvmx_usb_alloc_transaction(struct cvmx_usb_state *usb)
-{
-       struct cvmx_usb_transaction *t;
-       t = usb->free_transaction_head;
-       if (t) {
-               usb->free_transaction_head = t->next;
-               if (!usb->free_transaction_head)
-                       usb->free_transaction_tail = NULL;
-       }
-       if (t) {
-               memset(t, 0, sizeof(*t));
-               t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
-       }
-       return t;
-}
-
-
-/**
- * Free a usb transaction
- *
- * @usb:        USB device state populated by
- *              cvmx_usb_initialize().
- * @transaction:
- *              Transaction to free
- */
-static inline void __cvmx_usb_free_transaction(struct cvmx_usb_state *usb,
-                                              struct cvmx_usb_transaction *transaction)
-{
-       transaction->flags = 0;
-       transaction->prev = NULL;
-       transaction->next = NULL;
-       if (usb->free_transaction_tail)
-               usb->free_transaction_tail->next = transaction;
-       else
-               usb->free_transaction_head = transaction;
-       usb->free_transaction_tail = transaction;
-}
-
-
 /**
  * Add a pipe to the tail of a list
  * @list:   List to add pipe to
@@ -853,18 +727,7 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
        usb->init_flags = flags;
 
        /* Initialize the USB state structure */
-       {
-               int i;
-               usb->index = usb_port_number;
-
-               /* Initialize the transaction double linked list */
-               usb->free_transaction_head = NULL;
-               usb->free_transaction_tail = NULL;
-               for (i = 0; i < MAX_TRANSACTIONS; i++)
-                       __cvmx_usb_free_transaction(usb, usb->transaction + i);
-               for (i = 0; i < MAX_PIPES; i++)
-                       __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
-       }
+       usb->index = usb_port_number;
 
        /*
         * Power On Reset and PHY Initialization
@@ -890,16 +753,14 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
                 * source at USB_XO. USB_XI should be tied to GND.
                 * Most Octeon evaluation boards require this setting
                 */
-               if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
-                       /* From CN31XX,CN30XX manual */
-                       usbn_clk_ctl.cn31xx.p_rclk  = 1;
-                       usbn_clk_ctl.cn31xx.p_xenbn = 0;
-               } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
-                       /* From CN56XX,CN50XX manual */
-                       usbn_clk_ctl.cn56xx.p_rtype = 2;
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX) ||
+                   OCTEON_IS_MODEL(OCTEON_CN56XX) ||
+                   OCTEON_IS_MODEL(OCTEON_CN50XX))
+                       /* From CN56XX,CN50XX,CN31XX,CN30XX manuals */
+                       usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */
                else
                        /* From CN52XX manual */
-                       usbn_clk_ctl.cn52xx.p_rtype = 1;
+                       usbn_clk_ctl.s.p_rtype = 1;
 
                switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
                case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
@@ -917,16 +778,12 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
                 * The USB port uses a 12MHz crystal as clock source
                 * at USB_XO and USB_XI
                 */
-               if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
                        /* From CN31XX,CN30XX manual */
-                       usbn_clk_ctl.cn31xx.p_rclk  = 1;
-                       usbn_clk_ctl.cn31xx.p_xenbn = 1;
-               } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
-                       /* From CN56XX,CN50XX manual */
-                       usbn_clk_ctl.cn56xx.p_rtype = 0;
+                       usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */
                else
-                       /* From CN52XX manual */
-                       usbn_clk_ctl.cn52xx.p_rtype = 0;
+                       /* From CN56XX,CN52XX,CN50XX manuals. */
+                       usbn_clk_ctl.s.p_rtype = 0;
 
                usbn_clk_ctl.s.p_c_sel = 0;
        }
@@ -1282,9 +1139,7 @@ static int cvmx_usb_disable(struct cvmx_usb_state *usb)
  * determine if the usb port has anything connected, is enabled,
  * or has some sort of error condition. The return value of this
  * call has "changed" bits to signal of the value of some fields
- * have changed between calls. These "changed" fields are based
- * on the last call to cvmx_usb_set_status(). In order to clear
- * them, you must update the status through cvmx_usb_set_status().
+ * have changed between calls.
  *
  * @usb: USB device state populated by cvmx_usb_initialize().
  *
@@ -1308,58 +1163,6 @@ static struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *us
        return result;
 }
 
-
-/**
- * Set the current state of the USB port. The status is used as
- * a reference for the "changed" bits returned by
- * cvmx_usb_get_status(). Other than serving as a reference, the
- * status passed to this function is not used. No fields can be
- * changed through this call.
- *
- * @usb:        USB device state populated by cvmx_usb_initialize().
- * @port_status:
- *              Port status to set, most like returned by cvmx_usb_get_status()
- */
-static void cvmx_usb_set_status(struct cvmx_usb_state *usb,
-                               struct cvmx_usb_port_status port_status)
-{
-       usb->port_status = port_status;
-       return;
-}
-
-
-/**
- * Convert a USB transaction into a handle
- *
- * @usb:        USB device state populated by cvmx_usb_initialize().
- * @transaction:
- *              Transaction to get handle for
- *
- * Returns: Handle
- */
-static inline int __cvmx_usb_get_submit_handle(struct cvmx_usb_state *usb,
-                                              struct cvmx_usb_transaction *transaction)
-{
-       return ((unsigned long)transaction - (unsigned long)usb->transaction) /
-                       sizeof(*transaction);
-}
-
-
-/**
- * Convert a USB pipe into a handle
- *
- * @usb:        USB device state populated by cvmx_usb_initialize().
- * @pipe:       Pipe to get handle for
- *
- * Returns: Handle
- */
-static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_state *usb,
-                                            struct cvmx_usb_pipe *pipe)
-{
-       return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
-}
-
-
 /**
  * Open a virtual pipe between the host and a USB device. A pipe
  * must be opened before data can be transferred between a device
@@ -1410,52 +1213,54 @@ static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_state *usb,
  *                  this is only used for full/low speed
  *                  devices behind a high speed hub.
  *
- * Returns: A non negative value is a pipe handle. Negative
- *         values are error codes.
+ * Returns: A non-NULL value is a pipe. NULL means an error.
  */
-static int cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
-                             int device_addr, int endpoint_num,
-                             enum cvmx_usb_speed device_speed, int max_packet,
-                             enum cvmx_usb_transfer transfer_type,
-                             enum cvmx_usb_direction transfer_dir,
-                             int interval, int multi_count,
-                             int hub_device_addr, int hub_port)
+static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
+                                               int device_addr, int
+                                               endpoint_num,
+                                               enum cvmx_usb_speed
+                                                       device_speed,
+                                               int max_packet,
+                                               enum cvmx_usb_transfer
+                                                       transfer_type,
+                                               enum cvmx_usb_direction
+                                                       transfer_dir,
+                                               int interval, int multi_count,
+                                               int hub_device_addr,
+                                               int hub_port)
 {
        struct cvmx_usb_pipe *pipe;
 
        if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
-               return -EINVAL;
+               return NULL;
        if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
-               return -EINVAL;
+               return NULL;
        if (unlikely(device_speed > CVMX_USB_SPEED_LOW))
-               return -EINVAL;
+               return NULL;
        if (unlikely((max_packet <= 0) || (max_packet > 1024)))
-               return -EINVAL;
+               return NULL;
        if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
-               return -EINVAL;
+               return NULL;
        if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
                (transfer_dir != CVMX_USB_DIRECTION_IN)))
-               return -EINVAL;
+               return NULL;
        if (unlikely(interval < 0))
-               return -EINVAL;
+               return NULL;
        if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
-               return -EINVAL;
+               return NULL;
        if (unlikely(multi_count < 0))
-               return -EINVAL;
+               return NULL;
        if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
                (multi_count != 0)))
-               return -EINVAL;
+               return NULL;
        if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
-               return -EINVAL;
+               return NULL;
        if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
-               return -EINVAL;
+               return NULL;
 
-       /* Find a free pipe */
-       pipe = usb->free_pipes.head;
+       pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC);
        if (!pipe)
-               return -ENOMEM;
-       __cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
-       pipe->flags = __CVMX_USB_PIPE_FLAGS_OPEN;
+               return NULL;
        if ((device_speed == CVMX_USB_SPEED_HIGH) &&
                (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
                (transfer_type == CVMX_USB_TRANSFER_BULK))
@@ -1492,7 +1297,7 @@ static int cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
         * it doesn't have any submitted requests
         */
 
-       return __cvmx_usb_get_pipe_handle(usb, pipe);
+       return pipe;
 }
 
 
@@ -2206,51 +2011,107 @@ done:
        return;
 }
 
+static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p)
+{
+       return container_of(p, struct octeon_hcd, usb);
+}
 
-/**
- * Call a user's callback for a specific reason.
- *
- * @usb:        USB device state populated by cvmx_usb_initialize().
- * @pipe:       Pipe the callback is for or NULL
- * @transaction:
- *              Transaction the callback is for or NULL
- * @reason:     Reason this callback is being called
- * @complete_code:
- *              Completion code for the transaction, if any
- */
-static void __cvmx_usb_perform_callback(struct cvmx_usb_state *usb,
-                                       struct cvmx_usb_pipe *pipe,
-                                       struct cvmx_usb_transaction *transaction,
-                                       enum cvmx_usb_callback reason,
-                                       enum cvmx_usb_complete complete_code)
+static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
+{
+       return container_of((void *)p, struct usb_hcd, hcd_priv);
+}
+
+static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
+                                            enum cvmx_usb_complete status,
+                                            struct cvmx_usb_pipe *pipe,
+                                            struct cvmx_usb_transaction
+                                               *transaction,
+                                            int bytes_transferred,
+                                            struct urb *urb)
 {
-       cvmx_usb_callback_func_t callback = usb->callback[reason];
-       void *user_data = usb->callback_data[reason];
-       int submit_handle = -1;
-       int pipe_handle = -1;
-       int bytes_transferred = 0;
-
-       if (pipe)
-               pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
-
-       if (transaction) {
-               submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
-               bytes_transferred = transaction->actual_bytes;
-               /* Transactions are allowed to override the default callback */
-               if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) {
-                       callback = transaction->callback;
-                       user_data = transaction->callback_data;
+       struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
+       struct usb_hcd *hcd = octeon_to_hcd(priv);
+       struct device *dev = hcd->self.controller;
+
+       urb->actual_length = bytes_transferred;
+       urb->hcpriv = NULL;
+
+       if (!list_empty(&urb->urb_list))
+               /*
+                * It is on the dequeue_list, but we are going to call
+                * usb_hcd_giveback_urb(), so we must clear it from
+                * the list.  We got to it before the
+                * octeon_usb_urb_dequeue_work() tasklet did.
+                */
+               list_del_init(&urb->urb_list);
+
+       /* For Isochronous transactions we need to update the URB packet status
+          list from data in our private copy */
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               int i;
+               /*
+                * The pointer to the private list is stored in the setup_packet
+                * field.
+                */
+               struct cvmx_usb_iso_packet *iso_packet =
+                       (struct cvmx_usb_iso_packet *) urb->setup_packet;
+               /* Recalculate the transfer size by adding up each packet */
+               urb->actual_length = 0;
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       if (iso_packet[i].status == CVMX_USB_COMPLETE_SUCCESS) {
+                               urb->iso_frame_desc[i].status = 0;
+                               urb->iso_frame_desc[i].actual_length = iso_packet[i].length;
+                               urb->actual_length += urb->iso_frame_desc[i].actual_length;
+                       } else {
+                               dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n",
+                                       i, urb->number_of_packets,
+                                       iso_packet[i].status, pipe,
+                                       transaction, iso_packet[i].length);
+                               urb->iso_frame_desc[i].status = -EREMOTEIO;
+                       }
                }
+               /* Free the private list now that we don't need it anymore */
+               kfree(iso_packet);
+               urb->setup_packet = NULL;
        }
 
-       if (!callback)
-               return;
-
-       callback(usb, reason, complete_code, pipe_handle, submit_handle,
-                bytes_transferred, user_data);
+       switch (status) {
+       case CVMX_USB_COMPLETE_SUCCESS:
+               urb->status = 0;
+               break;
+       case CVMX_USB_COMPLETE_CANCEL:
+               if (urb->status == 0)
+                       urb->status = -ENOENT;
+               break;
+       case CVMX_USB_COMPLETE_STALL:
+               dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EPIPE;
+               break;
+       case CVMX_USB_COMPLETE_BABBLEERR:
+               dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EPIPE;
+               break;
+       case CVMX_USB_COMPLETE_SHORT:
+               dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EREMOTEIO;
+               break;
+       case CVMX_USB_COMPLETE_ERROR:
+       case CVMX_USB_COMPLETE_XACTERR:
+       case CVMX_USB_COMPLETE_DATATGLERR:
+       case CVMX_USB_COMPLETE_FRAMEERR:
+               dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n",
+                       status, pipe, transaction, bytes_transferred);
+               urb->status = -EPROTO;
+               break;
+       }
+       spin_unlock(&priv->lock);
+       usb_hcd_giveback_urb(octeon_to_hcd(priv), urb, urb->status);
+       spin_lock(&priv->lock);
 }
 
-
 /**
  * Signal the completion of a transaction and free it. The
  * transaction will be removed from the pipe transaction list.
@@ -2310,10 +2171,11 @@ static void __cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
                __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
 
        }
-       __cvmx_usb_perform_callback(usb, pipe, transaction,
-                                   CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
-                                   complete_code);
-       __cvmx_usb_free_transaction(usb, transaction);
+       octeon_usb_urb_complete_callback(usb, complete_code, pipe,
+                                        transaction,
+                                        transaction->actual_bytes,
+                                        transaction->urb);
+       kfree(transaction);
 done:
        return;
 }
@@ -2324,8 +2186,7 @@ done:
  * of transactions.
  *
  * @usb:
- * @pipe_handle:
- *                 Which pipe to submit to. Will be validated in this function.
+ * @pipe:          Which pipe to submit to.
  * @type:          Transaction type
  * @buffer:        User buffer for the transaction
  * @buffer_length:
@@ -2338,39 +2199,29 @@ done:
  *                 For ISO, the number of packet in the transaction.
  * @iso_packets:
  *                 A description of each ISO packet
- * @callback:      User callback to call when the transaction completes
- * @user_data:     User's data for the callback
+ * @urb:           URB for the callback
  *
- * Returns: Submit handle or negative on failure. Matches the result
- *         in the external API.
+ * Returns: Transaction or NULL on failure.
  */
-static int __cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
-                                        int pipe_handle,
-                                        enum cvmx_usb_transfer type,
-                                        uint64_t buffer,
-                                        int buffer_length,
-                                        uint64_t control_header,
-                                        int iso_start_frame,
-                                        int iso_number_packets,
-                                        struct cvmx_usb_iso_packet *iso_packets,
-                                        cvmx_usb_callback_func_t callback,
-                                        void *user_data)
+static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
+                                                                 struct cvmx_usb_pipe *pipe,
+                                                                 enum cvmx_usb_transfer type,
+                                                                 uint64_t buffer,
+                                                                 int buffer_length,
+                                                                 uint64_t control_header,
+                                                                 int iso_start_frame,
+                                                                 int iso_number_packets,
+                                                                 struct cvmx_usb_iso_packet *iso_packets,
+                                                                 struct urb *urb)
 {
-       int submit_handle;
        struct cvmx_usb_transaction *transaction;
-       struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
 
-       if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-               return -EINVAL;
-       /* Fail if the pipe isn't open */
-       if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-               return -EINVAL;
        if (unlikely(pipe->transfer_type != type))
-               return -EINVAL;
+               return NULL;
 
-       transaction = __cvmx_usb_alloc_transaction(usb);
+       transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC);
        if (unlikely(!transaction))
-               return -ENOMEM;
+               return NULL;
 
        transaction->type = type;
        transaction->buffer = buffer;
@@ -2380,8 +2231,7 @@ static int __cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
        transaction->iso_start_frame = iso_start_frame;
        transaction->iso_number_packets = iso_number_packets;
        transaction->iso_packets = iso_packets;
-       transaction->callback = callback;
-       transaction->callback_data = user_data;
+       transaction->urb = urb;
        if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
                transaction->stage = CVMX_USB_STAGE_SETUP;
        else
@@ -2402,13 +2252,11 @@ static int __cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
        }
        pipe->tail = transaction;
 
-       submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
-
        /* We may need to schedule the pipe if this was the head of the pipe */
        if (!transaction->prev)
                __cvmx_usb_schedule(usb, 0);
 
-       return submit_handle;
+       return transaction;
 }
 
 
@@ -2416,55 +2264,23 @@ static int __cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
  * Call to submit a USB Bulk transfer to a pipe.
  *
  * @usb:           USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *                 Handle to the pipe for the transfer.
- * @buffer:        Physical address of the data buffer in
- *                 memory. Note that this is NOT A POINTER, but
- *                 the full 64bit physical address of the
- *                 buffer. This may be zero if buffer_length is
- *                 zero.
- * @buffer_length:
- *                 Length of buffer in bytes.
- * @callback:      Function to call when this transaction
- *                 completes. If the return value of this
- *                 function isn't an error, then this function
- *                 is guaranteed to be called when the
- *                 transaction completes. If this parameter is
- *                 NULL, then the generic callback registered
- *                 through cvmx_usb_register_callback is
- *                 called. If both are NULL, then there is no
- *                 way to know when a transaction completes.
- * @user_data:     User supplied data returned when the
- *                 callback is called. This is only used if
- *                 callback in not NULL.
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB.
  *
- * Returns: A submitted transaction handle or negative on
- *         failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
  */
-static int cvmx_usb_submit_bulk(struct cvmx_usb_state *usb, int pipe_handle,
-                               uint64_t buffer, int buffer_length,
-                               cvmx_usb_callback_func_t callback,
-                               void *user_data)
+static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(struct cvmx_usb_state *usb,
+                                                        struct cvmx_usb_pipe *pipe,
+                                                        struct urb *urb)
 {
-       int submit_handle;
-
-       /* Pipe handle checking is done later in a common place */
-       if (unlikely(!buffer))
-               return -EINVAL;
-       if (unlikely(buffer_length < 0))
-               return -EINVAL;
-
-       submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                                     CVMX_USB_TRANSFER_BULK,
-                                                     buffer,
-                                                     buffer_length,
-                                                     0, /* control_header */
-                                                     0, /* iso_start_frame */
-                                                     0, /* iso_number_packets */
-                                                     NULL, /* iso_packets */
-                                                     callback,
-                                                     user_data);
-       return submit_handle;
+       return __cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK,
+                                            urb->transfer_dma,
+                                            urb->transfer_buffer_length,
+                                            0, /* control_header */
+                                            0, /* iso_start_frame */
+                                            0, /* iso_number_packets */
+                                            NULL, /* iso_packets */
+                                            urb);
 }
 
 
@@ -2472,56 +2288,24 @@ static int cvmx_usb_submit_bulk(struct cvmx_usb_state *usb, int pipe_handle,
  * Call to submit a USB Interrupt transfer to a pipe.
  *
  * @usb:           USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *                 Handle to the pipe for the transfer.
- * @buffer:        Physical address of the data buffer in
- *                 memory. Note that this is NOT A POINTER, but
- *                 the full 64bit physical address of the
- *                 buffer. This may be zero if buffer_length is
- *                 zero.
- * @buffer_length:
- *                 Length of buffer in bytes.
- * @callback:      Function to call when this transaction
- *                 completes. If the return value of this
- *                 function isn't an error, then this function
- *                 is guaranteed to be called when the
- *                 transaction completes. If this parameter is
- *                 NULL, then the generic callback registered
- *                 through cvmx_usb_register_callback is
- *                 called. If both are NULL, then there is no
- *                 way to know when a transaction completes.
- * @user_data:     User supplied data returned when the
- *                 callback is called. This is only used if
- *                 callback in not NULL.
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB returned when the callback is called.
  *
- * Returns: A submitted transaction handle or negative on
- *         failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
  */
-static int cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
-                                    int pipe_handle, uint64_t buffer,
-                                    int buffer_length,
-                                    cvmx_usb_callback_func_t callback,
-                                    void *user_data)
+static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
+                                                             struct cvmx_usb_pipe *pipe,
+                                                             struct urb *urb)
 {
-       int submit_handle;
-
-       /* Pipe handle checking is done later in a common place */
-       if (unlikely(!buffer))
-               return -EINVAL;
-       if (unlikely(buffer_length < 0))
-               return -EINVAL;
-
-       submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                                     CVMX_USB_TRANSFER_INTERRUPT,
-                                                     buffer,
-                                                     buffer_length,
-                                                     0, /* control_header */
-                                                     0, /* iso_start_frame */
-                                                     0, /* iso_number_packets */
-                                                     NULL, /* iso_packets */
-                                                     callback,
-                                                     user_data);
-       return submit_handle;
+       return __cvmx_usb_submit_transaction(usb, pipe,
+                                            CVMX_USB_TRANSFER_INTERRUPT,
+                                            urb->transfer_dma,
+                                            urb->transfer_buffer_length,
+                                            0, /* control_header */
+                                            0, /* iso_start_frame */
+                                            0, /* iso_number_packets */
+                                            NULL, /* iso_packets */
+                                            urb);
 }
 
 
@@ -2529,67 +2313,31 @@ static int cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
  * Call to submit a USB Control transfer to a pipe.
  *
  * @usb:           USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *                 Handle to the pipe for the transfer.
- * @control_header:
- *                 USB 8 byte control header physical address.
- *                 Note that this is NOT A POINTER, but the
- *                 full 64bit physical address of the buffer.
- * @buffer:        Physical address of the data buffer in
- *                 memory. Note that this is NOT A POINTER, but
- *                 the full 64bit physical address of the
- *                 buffer. This may be zero if buffer_length is
- *                 zero.
- * @buffer_length:
- *                 Length of buffer in bytes.
- * @callback:      Function to call when this transaction
- *                 completes. If the return value of this
- *                 function isn't an error, then this function
- *                 is guaranteed to be called when the
- *                 transaction completes. If this parameter is
- *                 NULL, then the generic callback registered
- *                 through cvmx_usb_register_callback is
- *                 called. If both are NULL, then there is no
- *                 way to know when a transaction completes.
- * @user_data:     User supplied data returned when the
- *                 callback is called. This is only used if
- *                 callback in not NULL.
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB.
  *
- * Returns: A submitted transaction handle or negative on
- *         failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
  */
-static int cvmx_usb_submit_control(struct cvmx_usb_state *usb,
-                                  int pipe_handle, uint64_t control_header,
-                                  uint64_t buffer, int buffer_length,
-                                  cvmx_usb_callback_func_t callback,
-                                  void *user_data)
+static struct cvmx_usb_transaction *cvmx_usb_submit_control(struct cvmx_usb_state *usb,
+                                                           struct cvmx_usb_pipe *pipe,
+                                                           struct urb *urb)
 {
-       int submit_handle;
+       int buffer_length = urb->transfer_buffer_length;
+       uint64_t control_header = urb->setup_dma;
        union cvmx_usb_control_header *header =
                cvmx_phys_to_ptr(control_header);
 
-       /* Pipe handle checking is done later in a common place */
-       if (unlikely(!control_header))
-               return -EINVAL;
-       /* Some drivers send a buffer with a zero length. God only knows why */
-       if (unlikely(buffer && (buffer_length < 0)))
-               return -EINVAL;
-       if (unlikely(!buffer && (buffer_length != 0)))
-               return -EINVAL;
        if ((header->s.request_type & 0x80) == 0)
                buffer_length = le16_to_cpu(header->s.length);
 
-       submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                                     CVMX_USB_TRANSFER_CONTROL,
-                                                     buffer,
-                                                     buffer_length,
-                                                     control_header,
-                                                     0, /* iso_start_frame */
-                                                     0, /* iso_number_packets */
-                                                     NULL, /* iso_packets */
-                                                     callback,
-                                                     user_data);
-       return submit_handle;
+       return __cvmx_usb_submit_transaction(usb, pipe,
+                                            CVMX_USB_TRANSFER_CONTROL,
+                                            urb->transfer_dma, buffer_length,
+                                            control_header,
+                                            0, /* iso_start_frame */
+                                            0, /* iso_number_packets */
+                                            NULL, /* iso_packets */
+                                            urb);
 }
 
 
@@ -2597,75 +2345,26 @@ static int cvmx_usb_submit_control(struct cvmx_usb_state *usb,
  * Call to submit a USB Isochronous transfer to a pipe.
  *
  * @usb:           USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *                 Handle to the pipe for the transfer.
- * @start_frame:
- *                 Number of frames into the future to schedule
- *                 this transaction.
- * @number_packets:
- *                 Number of sequential packets to transfer.
- *                 "packets" is a pointer to an array of this
- *                 many packet structures.
- * @packets:       Description of each transfer packet as
- *                 defined by struct cvmx_usb_iso_packet. The array
- *                 pointed to here must stay valid until the
- *                 complete callback is called.
- * @buffer:        Physical address of the data buffer in
- *                 memory. Note that this is NOT A POINTER, but
- *                 the full 64bit physical address of the
- *                 buffer. This may be zero if buffer_length is
- *                 zero.
- * @buffer_length:
- *                 Length of buffer in bytes.
- * @callback:      Function to call when this transaction
- *                 completes. If the return value of this
- *                 function isn't an error, then this function
- *                 is guaranteed to be called when the
- *                 transaction completes. If this parameter is
- *                 NULL, then the generic callback registered
- *                 through cvmx_usb_register_callback is
- *                 called. If both are NULL, then there is no
- *                 way to know when a transaction completes.
- * @user_data:     User supplied data returned when the
- *                 callback is called. This is only used if
- *                 callback in not NULL.
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB returned when the callback is called.
  *
- * Returns: A submitted transaction handle or negative on
- *         failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
  */
-static int cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
-                                      int pipe_handle, int start_frame,
-                                      int number_packets, struct
-                                      cvmx_usb_iso_packet packets[],
-                                      uint64_t buffer, int buffer_length,
-                                      cvmx_usb_callback_func_t callback,
-                                      void *user_data)
+static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
+                                                               struct cvmx_usb_pipe *pipe,
+                                                               struct urb *urb)
 {
-       int submit_handle;
-
-       /* Pipe handle checking is done later in a common place */
-       if (unlikely(start_frame < 0))
-               return -EINVAL;
-       if (unlikely(number_packets < 1))
-               return -EINVAL;
-       if (unlikely(!packets))
-               return -EINVAL;
-       if (unlikely(!buffer))
-               return -EINVAL;
-       if (unlikely(buffer_length < 0))
-               return -EINVAL;
-
-       submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                                     CVMX_USB_TRANSFER_ISOCHRONOUS,
-                                                     buffer,
-                                                     buffer_length,
-                                                     0, /* control_header */
-                                                     start_frame,
-                                                     number_packets,
-                                                     packets,
-                                                     callback,
-                                                     user_data);
-       return submit_handle;
+       struct cvmx_usb_iso_packet *packets;
+
+       packets = (struct cvmx_usb_iso_packet *) urb->setup_packet;
+       return __cvmx_usb_submit_transaction(usb, pipe,
+                                            CVMX_USB_TRANSFER_ISOCHRONOUS,
+                                            urb->transfer_dma,
+                                            urb->transfer_buffer_length,
+                                            0, /* control_header */
+                                            urb->start_frame,
+                                            urb->number_of_packets,
+                                            packets, urb);
 }
 
 
@@ -2677,35 +2376,15 @@ static int cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
  * associated callback.
  *
  * @usb:        USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *              Pipe handle to cancel requests in.
- * @submit_handle:
- *              Handle to transaction to cancel, returned by the submit
- *              function.
+ * @pipe:       Pipe to cancel requests in.
+ * @transaction: Transaction to cancel, returned by the submit function.
  *
  * Returns: 0 or a negative error code.
  */
-static int cvmx_usb_cancel(struct cvmx_usb_state *usb, int pipe_handle,
-                          int submit_handle)
+static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
+                          struct cvmx_usb_pipe *pipe,
+                          struct cvmx_usb_transaction *transaction)
 {
-       struct cvmx_usb_transaction *transaction;
-       struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
-       if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-               return -EINVAL;
-       if (unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
-               return -EINVAL;
-
-       /* Fail if the pipe isn't open */
-       if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-               return -EINVAL;
-
-       transaction = usb->transaction + submit_handle;
-
-       /* Fail if this transaction already completed */
-       if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
-               return -EINVAL;
-
        /*
         * If the transaction is the HEAD of the queue and scheduled. We need to
         * treat it special
@@ -2739,26 +2418,16 @@ static int cvmx_usb_cancel(struct cvmx_usb_state *usb, int pipe_handle,
  * does is call cvmx_usb_cancel() in a loop.
  *
  * @usb:        USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *              Pipe handle to cancel requests in.
+ * @pipe:       Pipe to cancel requests in.
  *
  * Returns: 0 or a negative error code.
  */
-static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb, int pipe_handle)
+static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
+                              struct cvmx_usb_pipe *pipe)
 {
-       struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
-       if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-               return -EINVAL;
-
-       /* Fail if the pipe isn't open */
-       if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-               return -EINVAL;
-
        /* Simply loop through and attempt to cancel each transaction */
        while (pipe->head) {
-               int result = cvmx_usb_cancel(usb, pipe_handle,
-                       __cvmx_usb_get_submit_handle(usb, pipe->head));
+               int result = cvmx_usb_cancel(usb, pipe, pipe->head);
                if (unlikely(result != 0))
                        return result;
        }
@@ -2770,62 +2439,24 @@ static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb, int pipe_handle)
  * Close a pipe created with cvmx_usb_open_pipe().
  *
  * @usb:        USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- *              Pipe handle to close.
+ * @pipe:       Pipe to close.
  *
  * Returns: 0 or a negative error code. EBUSY is returned if the pipe has
  *         outstanding transfers.
  */
-static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb, int pipe_handle)
+static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb,
+                              struct cvmx_usb_pipe *pipe)
 {
-       struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
-       if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-               return -EINVAL;
-
-       /* Fail if the pipe isn't open */
-       if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-               return -EINVAL;
-
        /* Fail if the pipe has pending transactions */
        if (unlikely(pipe->head))
                return -EBUSY;
 
-       pipe->flags = 0;
        __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
-       __cvmx_usb_append_pipe(&usb->free_pipes, pipe);
-
-       return 0;
-}
-
-
-/**
- * Register a function to be called when various USB events occur.
- *
- * @usb:       USB device state populated by cvmx_usb_initialize().
- * @reason:    Which event to register for.
- * @callback:  Function to call when the event occurs.
- * @user_data: User data parameter to the function.
- *
- * Returns: 0 or a negative error code.
- */
-static int cvmx_usb_register_callback(struct cvmx_usb_state *usb,
-                                     enum cvmx_usb_callback reason,
-                                     cvmx_usb_callback_func_t callback,
-                                     void *user_data)
-{
-       if (unlikely(reason >= __CVMX_USB_CALLBACK_END))
-               return -EINVAL;
-       if (unlikely(!callback))
-               return -EINVAL;
-
-       usb->callback[reason] = callback;
-       usb->callback_data[reason] = user_data;
+       kfree(pipe);
 
        return 0;
 }
 
-
 /**
  * Get the current USB protocol level frame number. The frame
  * number is always in the range of 0-0x7ff.
@@ -3286,6 +2917,14 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
        return 0;
 }
 
+static void octeon_usb_port_callback(struct cvmx_usb_state *usb)
+{
+       struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
+
+       spin_unlock(&priv->lock);
+       usb_hcd_poll_rh_status(octeon_to_hcd(priv));
+       spin_lock(&priv->lock);
+}
 
 /**
  * Poll the USB block for status and call all needed callback
@@ -3353,9 +2992,7 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
                 *
                 * Call the user's port callback
                 */
-               __cvmx_usb_perform_callback(usb, NULL, NULL,
-                                           CVMX_USB_CALLBACK_PORT_CHANGED,
-                                           CVMX_USB_COMPLETE_SUCCESS);
+               octeon_usb_port_callback(usb);
                /* Clear the port change bits */
                usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
                usbc_hprt.s.prtena = 0;
@@ -3396,16 +3033,6 @@ static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd)
        return (struct octeon_hcd *)(hcd->hcd_priv);
 }
 
-static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
-{
-       return container_of((void *)p, struct usb_hcd, hcd_priv);
-}
-
-static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p)
-{
-       return container_of(p, struct octeon_hcd, usb);
-}
-
 static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
 {
        struct octeon_hcd *priv = hcd_to_octeon(hcd);
@@ -3417,43 +3044,14 @@ static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
        return IRQ_HANDLED;
 }
 
-static void octeon_usb_port_callback(struct cvmx_usb_state *usb,
-                                    enum cvmx_usb_callback reason,
-                                    enum cvmx_usb_complete status,
-                                    int pipe_handle,
-                                    int submit_handle,
-                                    int bytes_transferred,
-                                    void *user_data)
-{
-       struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
-
-       spin_unlock(&priv->lock);
-       usb_hcd_poll_rh_status(octeon_to_hcd(priv));
-       spin_lock(&priv->lock);
-}
-
 static int octeon_usb_start(struct usb_hcd *hcd)
 {
-       struct octeon_hcd *priv = hcd_to_octeon(hcd);
-       unsigned long flags;
-
        hcd->state = HC_STATE_RUNNING;
-       spin_lock_irqsave(&priv->lock, flags);
-       cvmx_usb_register_callback(&priv->usb, CVMX_USB_CALLBACK_PORT_CHANGED,
-                                  octeon_usb_port_callback, NULL);
-       spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
 }
 
 static void octeon_usb_stop(struct usb_hcd *hcd)
 {
-       struct octeon_hcd *priv = hcd_to_octeon(hcd);
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       cvmx_usb_register_callback(&priv->usb, CVMX_USB_CALLBACK_PORT_CHANGED,
-                                  NULL, NULL);
-       spin_unlock_irqrestore(&priv->lock, flags);
        hcd->state = HC_STATE_HALT;
 }
 
@@ -3464,109 +3062,14 @@ static int octeon_usb_get_frame_number(struct usb_hcd *hcd)
        return cvmx_usb_get_frame_number(&priv->usb);
 }
 
-static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
-                                            enum cvmx_usb_callback reason,
-                                            enum cvmx_usb_complete status,
-                                            int pipe_handle,
-                                            int submit_handle,
-                                            int bytes_transferred,
-                                            void *user_data)
-{
-       struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
-       struct usb_hcd *hcd = octeon_to_hcd(priv);
-       struct device *dev = hcd->self.controller;
-       struct urb *urb = user_data;
-
-       urb->actual_length = bytes_transferred;
-       urb->hcpriv = NULL;
-
-       if (!list_empty(&urb->urb_list)) {
-               /*
-                * It is on the dequeue_list, but we are going to call
-                * usb_hcd_giveback_urb(), so we must clear it from
-                * the list.  We got to it before the
-                * octeon_usb_urb_dequeue_work() tasklet did.
-                */
-               list_del(&urb->urb_list);
-               /* No longer on the dequeue_list. */
-               INIT_LIST_HEAD(&urb->urb_list);
-       }
-
-       /* For Isochronous transactions we need to update the URB packet status
-          list from data in our private copy */
-       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-               int i;
-               /*
-                * The pointer to the private list is stored in the setup_packet
-                * field.
-                */
-               struct cvmx_usb_iso_packet *iso_packet =
-                       (struct cvmx_usb_iso_packet *) urb->setup_packet;
-               /* Recalculate the transfer size by adding up each packet */
-               urb->actual_length = 0;
-               for (i = 0; i < urb->number_of_packets; i++) {
-                       if (iso_packet[i].status == CVMX_USB_COMPLETE_SUCCESS) {
-                               urb->iso_frame_desc[i].status = 0;
-                               urb->iso_frame_desc[i].actual_length = iso_packet[i].length;
-                               urb->actual_length += urb->iso_frame_desc[i].actual_length;
-                       } else {
-                               dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%d submit=%d size=%d\n",
-                                       i, urb->number_of_packets,
-                                       iso_packet[i].status, pipe_handle,
-                                       submit_handle, iso_packet[i].length);
-                               urb->iso_frame_desc[i].status = -EREMOTEIO;
-                       }
-               }
-               /* Free the private list now that we don't need it anymore */
-               kfree(iso_packet);
-               urb->setup_packet = NULL;
-       }
-
-       switch (status) {
-       case CVMX_USB_COMPLETE_SUCCESS:
-               urb->status = 0;
-               break;
-       case CVMX_USB_COMPLETE_CANCEL:
-               if (urb->status == 0)
-                       urb->status = -ENOENT;
-               break;
-       case CVMX_USB_COMPLETE_STALL:
-               dev_dbg(dev, "status=stall pipe=%d submit=%d size=%d\n",
-                       pipe_handle, submit_handle, bytes_transferred);
-               urb->status = -EPIPE;
-               break;
-       case CVMX_USB_COMPLETE_BABBLEERR:
-               dev_dbg(dev, "status=babble pipe=%d submit=%d size=%d\n",
-                       pipe_handle, submit_handle, bytes_transferred);
-               urb->status = -EPIPE;
-               break;
-       case CVMX_USB_COMPLETE_SHORT:
-               dev_dbg(dev, "status=short pipe=%d submit=%d size=%d\n",
-                       pipe_handle, submit_handle, bytes_transferred);
-               urb->status = -EREMOTEIO;
-               break;
-       case CVMX_USB_COMPLETE_ERROR:
-       case CVMX_USB_COMPLETE_XACTERR:
-       case CVMX_USB_COMPLETE_DATATGLERR:
-       case CVMX_USB_COMPLETE_FRAMEERR:
-               dev_dbg(dev, "status=%d pipe=%d submit=%d size=%d\n",
-                       status, pipe_handle, submit_handle, bytes_transferred);
-               urb->status = -EPROTO;
-               break;
-       }
-       spin_unlock(&priv->lock);
-       usb_hcd_giveback_urb(octeon_to_hcd(priv), urb, urb->status);
-       spin_lock(&priv->lock);
-}
-
 static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
                                  struct urb *urb,
                                  gfp_t mem_flags)
 {
        struct octeon_hcd *priv = hcd_to_octeon(hcd);
        struct device *dev = hcd->self.controller;
-       int submit_handle = -1;
-       int pipe_handle;
+       struct cvmx_usb_transaction *transaction = NULL;
+       struct cvmx_usb_pipe *pipe;
        unsigned long flags;
        struct cvmx_usb_iso_packet *iso_packet;
        struct usb_host_endpoint *ep = urb->ep;
@@ -3635,25 +3138,24 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
                                dev = dev->parent;
                        }
                }
-               pipe_handle = cvmx_usb_open_pipe(&priv->usb,
-                                                usb_pipedevice(urb->pipe),
-                                                usb_pipeendpoint(urb->pipe),
-                                                speed,
-                                                le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff,
-                                                transfer_type,
-                                                usb_pipein(urb->pipe) ? CVMX_USB_DIRECTION_IN : CVMX_USB_DIRECTION_OUT,
-                                                urb->interval,
-                                                (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3,
-                                                split_device,
-                                                split_port);
-               if (pipe_handle < 0) {
+               pipe = cvmx_usb_open_pipe(&priv->usb, usb_pipedevice(urb->pipe),
+                                         usb_pipeendpoint(urb->pipe), speed,
+                                         le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff,
+                                         transfer_type,
+                                         usb_pipein(urb->pipe) ?
+                                               CVMX_USB_DIRECTION_IN :
+                                               CVMX_USB_DIRECTION_OUT,
+                                         urb->interval,
+                                         (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3,
+                                         split_device, split_port);
+               if (!pipe) {
                        spin_unlock_irqrestore(&priv->lock, flags);
                        dev_dbg(dev, "Failed to create pipe\n");
                        return -ENOMEM;
                }
-               ep->hcpriv = (void *)(0x10000L + pipe_handle);
+               ep->hcpriv = pipe;
        } else {
-               pipe_handle = 0xffff & (long)ep->hcpriv;
+               pipe = ep->hcpriv;
        }
 
        switch (usb_pipetype(urb->pipe)) {
@@ -3681,19 +3183,13 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
                         * this saves us a bunch of logic.
                         */
                        urb->setup_packet = (char *)iso_packet;
-                       submit_handle = cvmx_usb_submit_isochronous(&priv->usb, pipe_handle,
-                                                       urb->start_frame,
-                                                       urb->number_of_packets,
-                                                       iso_packet,
-                                                       urb->transfer_dma,
-                                                       urb->transfer_buffer_length,
-                                                       octeon_usb_urb_complete_callback,
-                                                       urb);
+                       transaction = cvmx_usb_submit_isochronous(&priv->usb,
+                                                                 pipe, urb);
                        /*
                         * If submit failed we need to free our private packet
                         * list.
                         */
-                       if (submit_handle < 0) {
+                       if (!transaction) {
                                urb->setup_packet = NULL;
                                kfree(iso_packet);
                        }
@@ -3702,59 +3198,41 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
        case PIPE_INTERRUPT:
                dev_dbg(dev, "Submit interrupt to %d.%d\n",
                        usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
-               submit_handle = cvmx_usb_submit_interrupt(&priv->usb, pipe_handle,
-                                             urb->transfer_dma,
-                                             urb->transfer_buffer_length,
-                                             octeon_usb_urb_complete_callback,
-                                             urb);
+               transaction = cvmx_usb_submit_interrupt(&priv->usb, pipe, urb);
                break;
        case PIPE_CONTROL:
                dev_dbg(dev, "Submit control to %d.%d\n",
                        usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
-               submit_handle = cvmx_usb_submit_control(&priv->usb, pipe_handle,
-                                           urb->setup_dma,
-                                           urb->transfer_dma,
-                                           urb->transfer_buffer_length,
-                                           octeon_usb_urb_complete_callback,
-                                           urb);
+               transaction = cvmx_usb_submit_control(&priv->usb, pipe, urb);
                break;
        case PIPE_BULK:
                dev_dbg(dev, "Submit bulk to %d.%d\n",
                        usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
-               submit_handle = cvmx_usb_submit_bulk(&priv->usb, pipe_handle,
-                                        urb->transfer_dma,
-                                        urb->transfer_buffer_length,
-                                        octeon_usb_urb_complete_callback,
-                                        urb);
+               transaction = cvmx_usb_submit_bulk(&priv->usb, pipe, urb);
                break;
        }
-       if (submit_handle < 0) {
+       if (!transaction) {
                spin_unlock_irqrestore(&priv->lock, flags);
                dev_dbg(dev, "Failed to submit\n");
                return -ENOMEM;
        }
-       urb->hcpriv = (void *)(long)(((submit_handle & 0xffff) << 16) | pipe_handle);
+       urb->hcpriv = transaction;
        spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
 }
 
 static void octeon_usb_urb_dequeue_work(unsigned long arg)
 {
+       struct urb *urb;
+       struct urb *next;
        unsigned long flags;
        struct octeon_hcd *priv = (struct octeon_hcd *)arg;
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       while (!list_empty(&priv->dequeue_list)) {
-               int pipe_handle;
-               int submit_handle;
-               struct urb *urb = container_of(priv->dequeue_list.next, struct urb, urb_list);
-               list_del(&urb->urb_list);
-               /* not enqueued on dequeue_list */
-               INIT_LIST_HEAD(&urb->urb_list);
-               pipe_handle = 0xffff & (long)urb->hcpriv;
-               submit_handle = ((long)urb->hcpriv) >> 16;
-               cvmx_usb_cancel(&priv->usb, pipe_handle, submit_handle);
+       list_for_each_entry_safe(urb, next, &priv->dequeue_list, urb_list) {
+               list_del_init(&urb->urb_list);
+               cvmx_usb_cancel(&priv->usb, urb->ep->hcpriv, urb->hcpriv);
        }
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -3786,12 +3264,12 @@ static void octeon_usb_endpoint_disable(struct usb_hcd *hcd, struct usb_host_end
 
        if (ep->hcpriv) {
                struct octeon_hcd *priv = hcd_to_octeon(hcd);
-               int pipe_handle = 0xffff & (long)ep->hcpriv;
+               struct cvmx_usb_pipe *pipe = ep->hcpriv;
                unsigned long flags;
                spin_lock_irqsave(&priv->lock, flags);
-               cvmx_usb_cancel_all(&priv->usb, pipe_handle);
-               if (cvmx_usb_close_pipe(&priv->usb, pipe_handle))
-                       dev_dbg(dev, "Closing pipe %d failed\n", pipe_handle);
+               cvmx_usb_cancel_all(&priv->usb, pipe);
+               if (cvmx_usb_close_pipe(&priv->usb, pipe))
+                       dev_dbg(dev, "Closing pipe %p failed\n", pipe);
                spin_unlock_irqrestore(&priv->lock, flags);
                ep->hcpriv = NULL;
        }
@@ -3863,7 +3341,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        dev_dbg(dev, " C_CONNECTION\n");
                        /* Clears drivers internal connect status change flag */
                        spin_lock_irqsave(&priv->lock, flags);
-                       cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb));
+                       priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        break;
                case USB_PORT_FEAT_C_RESET:
@@ -3872,7 +3350,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                         * Clears the driver's internal Port Reset Change flag.
                         */
                        spin_lock_irqsave(&priv->lock, flags);
-                       cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb));
+                       priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        break;
                case USB_PORT_FEAT_C_ENABLE:
@@ -3882,7 +3360,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                         * Change flag.
                         */
                        spin_lock_irqsave(&priv->lock, flags);
-                       cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb));
+                       priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
@@ -3897,7 +3375,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        dev_dbg(dev, " C_OVER_CURRENT\n");
                        /* Clears the driver's overcurrent Change flag */
                        spin_lock_irqsave(&priv->lock, flags);
-                       cvmx_usb_set_status(&priv->usb, cvmx_usb_get_status(&priv->usb));
+                       priv->usb.port_status = cvmx_usb_get_status(&priv->usb);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        break;
                default:
This page took 0.048121 seconds and 5 git commands to generate.