/*
* WUSB Wire Adapter
* Data transfer and URB enqueing
*
* Copyright (C) 2005-2006 Intel Corporation
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* How transfers work: get a buffer, break it up in segments (segment
* size is a multiple of the maxpacket size). For each segment issue a
* segment request (struct wa_xfer_*), then send the data buffer if
* out or nothing if in (all over the DTO endpoint).
*
* For each submitted segment request, a notification will come over
* the NEP endpoint and a transfer result (struct xfer_result) will
* arrive in the DTI URB. Read it, get the xfer ID, see if there is
* data coming (inbound transfer), schedule a read and handle it.
*
* Sounds simple, it is a pain to implement.
*
*
* ENTRY POINTS
*
* FIXME
*
* LIFE CYCLE / STATE DIAGRAM
*
* FIXME
*
* THIS CODE IS DISGUSTING
*
* Warned you are; it's my second try and still not happy with it.
*
* NOTES:
*
* - No iso
*
* - Supports DMA xfers, control, bulk and maybe interrupt
*
* - Does not recycle unused rpipes
*
* An rpipe is assigned to an endpoint the first time it is used,
* and then it's there, assigned, until the endpoint is disabled
* (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
* rpipe to the endpoint is done under the wa->rpipe_sem semaphore
* (should be a mutex).
*
* Two methods it could be done:
*
* (a) set up a timer every time an rpipe's use count drops to 1
* (which means unused) or when a transfer ends. Reset the
* timer when a xfer is queued. If the timer expires, release
* the rpipe [see rpipe_ep_disable()].
*
* (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
* when none are found go over the list, check their endpoint
* and their activity record (if no last-xfer-done-ts in the
* last x seconds) take it
*
* However, due to the fact that we have a set of limited
* resources (max-segments-at-the-same-time per xfer,
* xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
* we are going to have to rebuild all this based on an scheduler,
* to where we have a list of transactions to do and based on the
* availability of the different required components (blocks,
* rpipes, segment slots, etc), we go scheduling them. Painful.
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/hash.h>
#include <linux/ratelimit.h>
#include <linux/export.h>
#include "wa-hc.h"
#include "wusbhc.h"
enum {
WA_SEGS_MAX = 255,
};
enum wa_seg_status {
WA_SEG_NOTREADY,
WA_SEG_READY,
WA_SEG_DELAYED,
WA_SEG_SUBMITTED,
WA_SEG_PENDING,
WA_SEG_DTI_PENDING,
WA_SEG_DONE,
WA_SEG_ERROR,
WA_SEG_ABORTED,
};
static void wa_xfer_delayed_run(struct wa_rpipe *);
/*
* Life cycle governed by 'struct urb' (the refcount of the struct is
* that of the 'struct urb' and usb_free_urb() would free the whole
* struct).
*/
struct wa_seg {
struct urb urb;
struct urb *dto_urb; /* for data output? */
struct list_head list_node; /* for rpipe->req_list */
struct wa_xfer *xfer; /* out xfer */
u8 index; /* which segment we are */
enum wa_seg_status status;
ssize_t result; /* bytes xfered or error */
struct wa_xfer_hdr xfer_hdr;
u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */
};
static void wa_seg_init(struct wa_seg *seg)
{
/* usb_init_urb() repeats a lot of work, so we do it here */
kref_init(&seg->urb.kref);
}
/*
* Protected by xfer->l
|