/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
#include "common.h"
#include "pipe.h"
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo))
#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo))
#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
/*
* packet initialize
*/
void usbhs_pkt_init(struct usbhs_pkt *pkt)
{
pkt->dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&pkt->node);
}
/*
* packet control function
*/
static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe);
struct device *dev = usbhs_priv_to_dev(priv);
dev_err(dev, "null handler\n");
return -EINVAL;
}
static struct usbhs_pkt_handle usbhsf_null_handler = {
.prepare = usbhsf_null_handle,
.try_run = usbhsf_null_handle,
};
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt),
void *buf, int len, int zero, int sequence)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct device *dev = usbhs_priv_to_dev(priv);
unsigned long flags;
if (!done) {
dev_err(dev, "no done function\n");
return;
}
/******************** spin lock ********************/
usbhs_lock(priv, flags);
if (!pipe->handler) {
dev_err(dev, "no handler function\n");
pipe->handler = &usbhsf_null_handler;
}
list_move_tail(&pkt->node, &pipe->list);
/*
* each pkt must hold own handler.
* because handler might be changed by its situation.
* dma handler -> pio handler.
*/
pkt->pipe = pipe;
pkt->buf = buf;
pkt->handler = pipe->handler;
pkt->length = len;
pkt->zero = zero;
pkt->actual = 0;
pkt->done = done;
pkt->sequence = sequence;
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
}
static void __usbhsf_pkt_del(struct usbhs_pkt *pkt)
{
list_del_init(&pkt->node);
}
static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
{
if (list_empty(&pipe->list))
return NULL;
return list_first_entry(&pipe->list, struct usbhs_pkt, node);
}
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
unsigned long<