Skip to content

Commit

Permalink
usb: renesas_usbhs: modify data transfer method
Browse files Browse the repository at this point in the history
On current driver, main data transfer function was implemented in fifo.c,
but the overall controlling was implementing in mod_gadget.c.
This style is not useful to support host and DMAEngine in the future.

But the interrupt for data transfer cannot separate easily for now,
because it is deeply related to mod_gadget.

This patch move the overall data transfer method
into fifo.c except interrupt.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Kuninori Morimoto authored and Greg Kroah-Hartman committed Jun 7, 2011
1 parent 6acb95d commit 659d495
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 163 deletions.
168 changes: 130 additions & 38 deletions drivers/usb/renesas_usbhs/fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,17 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt)
INIT_LIST_HEAD(&pkt->node);
}

void usbhs_pkt_update(struct usbhs_pkt *pkt, void *buf, int len)
{
pkt->buf = buf;
pkt->length = len;
pkt->actual = 0;
pkt->maxp = 0;
}

void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void *buf, int len, int zero)
{
list_del_init(&pkt->node);
list_add_tail(&pkt->node, &pipe->list);

pkt->pipe = pipe;
pkt->pipe = pipe;
pkt->buf = buf;
pkt->length = len;
pkt->zero = zero;
pkt->actual = 0;
}

void usbhs_pkt_pop(struct usbhs_pkt *pkt)
Expand All @@ -56,6 +53,47 @@ struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe)
return list_entry(pipe->list.next, struct usbhs_pkt, node);
}

/*
* irq enable/disable function
*/
#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e)
#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e)
#define usbhsf_irq_callback_ctrl(pipe, status, enable) \
({ \
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \
struct usbhs_mod *mod = usbhs_mod_get_current(priv); \
u16 status = (1 << usbhs_pipe_number(pipe)); \
if (!mod) \
return; \
if (enable) \
mod->irq_##status |= status; \
else \
mod->irq_##status &= ~status; \
usbhs_irq_callback_update(priv, mod); \
})

static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable)
{
/*
* And DCP pipe can NOT use "ready interrupt" for "send"
* it should use "empty" interrupt.
* see
* "Operation" - "Interrupt Function" - "BRDY Interrupt"
*
* on the other hand, normal pipe can use "ready interrupt" for "send"
* even though it is single/double buffer
*/
if (usbhs_pipe_is_dcp(pipe))
usbhsf_irq_empty_ctrl(pipe, enable);
else
usbhsf_irq_ready_ctrl(pipe, enable);
}

static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable)
{
usbhsf_irq_ready_ctrl(pipe, enable);
}

/*
* FIFO ctrl
*/
Expand Down Expand Up @@ -135,34 +173,38 @@ int usbhs_fifo_write(struct usbhs_pkt *pkt)
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct device *dev = usbhs_priv_to_dev(priv);
void __iomem *addr = priv->base + CFIFO;
u8 *buf;
int maxp = usbhs_pipe_get_maxpacket(pipe);
int total_len;
u8 *buf = pkt->buf;
int i, ret, len;
int is_short, is_done;

ret = usbhs_pipe_is_accessible(pipe);
if (ret < 0)
return ret;
goto usbhs_fifo_write_busy;

ret = usbhsf_fifo_select(pipe, 1);
if (ret < 0)
return ret;
goto usbhs_fifo_write_busy;

ret = usbhsf_fifo_barrier(priv);
if (ret < 0)
return ret;
goto usbhs_fifo_write_busy;

len = min(pkt->length, maxp);
total_len = len;
buf = pkt->buf + pkt->actual;
len = pkt->length - pkt->actual;
len = min(len, maxp);
total_len = len;
is_short = total_len < maxp;

/*
* FIXME
*
* 32-bit access only
*/
if (len >= 4 &&
!((unsigned long)buf & 0x03)) {
if (len >= 4 && !((unsigned long)buf & 0x03)) {
iowrite32_rep(addr, buf, len / 4);
len %= 4;
buf += total_len - len;
Expand All @@ -172,19 +214,52 @@ int usbhs_fifo_write(struct usbhs_pkt *pkt)
for (i = 0; i < len; i++)
iowrite8(buf[i], addr + (0x03 - (i & 0x03)));

if (total_len < maxp)
/*
* variable update
*/
pkt->actual += total_len;

if (pkt->actual < pkt->length)
is_done = 0; /* there are remainder data */
else if (is_short)
is_done = 1; /* short packet */
else
is_done = !pkt->zero; /* send zero packet ? */

/*
* pipe/irq handling
*/
if (is_short)
usbhsf_send_terminator(pipe);

usbhsf_tx_irq_ctrl(pipe, !is_done);
usbhs_pipe_enable(pipe);

/* update pkt */
if (info->tx_done) {
pkt->actual = total_len;
pkt->maxp = maxp;
info->tx_done(pkt);
dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n",
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, is_done, pkt->zero);

/*
* Transmission end
*/
if (is_done) {
if (usbhs_pipe_is_dcp(pipe))
usbhs_dcp_control_transfer_done(pipe);

if (info->tx_done)
info->tx_done(pkt);
}

return 0;

usbhs_fifo_write_busy:
/*
* pipe is busy.
* retry in interrupt
*/
usbhsf_tx_irq_ctrl(pipe, 1);

return ret;
}

int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
Expand All @@ -199,6 +274,7 @@ int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
return ret;

usbhs_pipe_enable(pipe);
usbhsf_rx_irq_ctrl(pipe, 1);

return ret;
}
Expand All @@ -207,13 +283,15 @@ int usbhs_fifo_read(struct usbhs_pkt *pkt)
{
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct device *dev = usbhs_priv_to_dev(priv);
void __iomem *addr = priv->base + CFIFO;
u8 *buf = pkt->buf;
u8 *buf;
u32 data = 0;
int maxp = usbhs_pipe_get_maxpacket(pipe);
int rcv_len, len;
int i, ret;
int total_len = 0;
u32 data = 0;
int is_done = 0;

ret = usbhsf_fifo_select(pipe, 0);
if (ret < 0)
Expand All @@ -225,6 +303,11 @@ int usbhs_fifo_read(struct usbhs_pkt *pkt)

rcv_len = usbhsf_fifo_rcv_len(priv);

buf = pkt->buf + pkt->actual;
len = pkt->length - pkt->actual;
len = min(len, rcv_len);
total_len = len;

/*
* Buffer clear if Zero-Length packet
*
Expand All @@ -236,19 +319,15 @@ int usbhs_fifo_read(struct usbhs_pkt *pkt)
goto usbhs_fifo_read_end;
}

len = min(rcv_len, pkt->length);
total_len = len;

/*
* FIXME
*
* 32-bit access only
*/
if (len >= 4 &&
!((unsigned long)buf & 0x03)) {
if (len >= 4 && !((unsigned long)buf & 0x03)) {
ioread32_rep(addr, buf, len / 4);
len %= 4;
buf += rcv_len - len;
buf += total_len - len;
}

/* the rest operation */
Expand All @@ -259,12 +338,25 @@ int usbhs_fifo_read(struct usbhs_pkt *pkt)
buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
}

pkt->actual += total_len;

usbhs_fifo_read_end:
if (info->rx_done) {
/* update pkt */
pkt->actual = total_len;
pkt->maxp = usbhs_pipe_get_maxpacket(pipe);
info->rx_done(pkt);
if ((pkt->actual == pkt->length) || /* receive all data */
(total_len < maxp)) /* short packet */
is_done = 1;

dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n",
usbhs_pipe_number(pipe),
pkt->length, pkt->actual, is_done, pkt->zero);

if (is_done) {
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);

usbhsf_rx_irq_ctrl(pipe, 0);
usbhs_pipe_disable(pipe);

if (info->rx_done)
info->rx_done(pkt);
}

return 0;
Expand Down
6 changes: 3 additions & 3 deletions drivers/usb/renesas_usbhs/fifo.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
struct usbhs_pkt {
struct list_head node;
struct usbhs_pipe *pipe;
int maxp;
void *buf;
int length;
int actual;
int zero;
};

/*
Expand All @@ -40,8 +40,8 @@ int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);
* packet info
*/
void usbhs_pkt_init(struct usbhs_pkt *pkt);
void usbhs_pkt_update(struct usbhs_pkt *pkt, void *buf, int len);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void *buf, int len, int zero);
void usbhs_pkt_pop(struct usbhs_pkt *pkt);
struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe);

Expand Down
Loading

0 comments on commit 659d495

Please sign in to comment.