diff options
-rw-r--r-- | drivers/usb/renesas_usbhs/common.h | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.c | 57 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/fifo.h | 21 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_gadget.c | 115 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 8 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.h | 8 |
6 files changed, 150 insertions, 60 deletions
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 24f756024bed..0aadcb402764 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -24,7 +24,6 @@ struct usbhs_priv; #include "./mod.h" #include "./pipe.h" -#include "./fifo.h" /* * diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 3fd3adf90541..098388489813 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -20,6 +20,20 @@ #include "./pipe.h" /* + * packet info function + */ +void usbhs_pkt_update(struct usbhs_pkt *pkt, + struct usbhs_pipe *pipe, + void *buf, int len) +{ + pkt->pipe = pipe; + pkt->buf = buf; + pkt->length = len; + pkt->actual = 0; + pkt->maxp = 0; +} + +/* * FIFO ctrl */ static void usbhsf_send_terminator(struct usbhs_pipe *pipe) @@ -93,13 +107,16 @@ int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe) return usbhsf_fifo_select(pipe, 1); } -int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len) +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); void __iomem *addr = priv->base + CFIFO; int maxp = usbhs_pipe_get_maxpacket(pipe); int total_len; - int i, ret; + u8 *buf = pkt->buf; + int i, ret, len; ret = usbhs_pipe_is_accessible(pipe); if (ret < 0) @@ -113,7 +130,7 @@ int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len) if (ret < 0) return ret; - len = min(len, maxp); + len = min(pkt->length, maxp); total_len = len; /* @@ -135,7 +152,16 @@ int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len) if (total_len < maxp) usbhsf_send_terminator(pipe); - return total_len; + usbhs_pipe_enable(pipe); + + /* update pkt */ + if (info->tx_done) { + pkt->actual = total_len; + pkt->maxp = maxp; + info->tx_done(pkt); + } + + return 0; } int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe) @@ -154,13 +180,16 @@ int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe) return ret; } -int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len) +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); void __iomem *addr = priv->base + CFIFO; - int rcv_len; + u8 *buf = pkt->buf; + int rcv_len, len; int i, ret; - int total_len; + int total_len = 0; u32 data = 0; ret = usbhsf_fifo_select(pipe, 0); @@ -181,10 +210,10 @@ int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len) */ if (0 == rcv_len) { usbhsf_fifo_clear(pipe); - return 0; + goto usbhs_fifo_read_end; } - len = min(rcv_len, len); + len = min(rcv_len, pkt->length); total_len = len; /* @@ -207,5 +236,13 @@ int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len) buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; } - return 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); + } + + return 0; } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 75a7c1577ad3..758d85dd31dd 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -17,14 +17,29 @@ #ifndef RENESAS_USB_FIFO_H #define RENESAS_USB_FIFO_H -#include "common.h" +#include "pipe.h" + +struct usbhs_pkt { + struct usbhs_pipe *pipe; + int maxp; + void *buf; + int length; + int actual; +}; /* * fifo */ -int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len); -int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len); +int usbhs_fifo_write(struct usbhs_pkt *pkt); +int usbhs_fifo_read(struct usbhs_pkt *pkt); int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe); int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe); +/* + * packet info + */ +void usbhs_pkt_update(struct usbhs_pkt *pkt, + struct usbhs_pipe *pipe, + void *buf, int len); + #endif /* RENESAS_USB_FIFO_H */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 128c8da8db85..4a1d1fcc90fd 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -27,6 +27,7 @@ struct usbhsg_request { struct usb_request req; struct list_head node; + struct usbhs_pkt pkt; }; #define EP_NAME_SIZE 8 @@ -110,6 +111,10 @@ struct usbhsg_recip_handle { #define usbhsg_pipe_to_uep(p) ((p)->mod_private) #define usbhsg_is_dcp(u) ((u) == usbhsg_gpriv_to_dcp((u)->gpriv)) +#define usbhsg_ureq_to_pkt(u) (&(u)->pkt) +#define usbhsg_pkt_to_ureq(i) \ + container_of(i, struct usbhsg_request, pkt) + #define usbhsg_is_not_connected(gp) ((gp)->gadget.speed == USB_SPEED_UNKNOWN) /* status */ @@ -319,38 +324,32 @@ static int usbhsg_try_run_ctrl_stage_end(struct usbhsg_uep *uep, return 0; } -static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) +/* + * packet send hander + */ +static void usbhsg_try_run_send_packet_bh(struct usbhs_pkt *pkt) { - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); + struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); - void *buf; - int remainder, send; + int remainder, send, maxp; int is_done = 0; int enable; - int maxp; - /* - ********* assume under spin lock ********* - */ - - maxp = usbhs_pipe_get_maxpacket(pipe); - buf = req->buf + req->actual; - remainder = req->length - req->actual; - - send = usbhs_fifo_write(pipe, buf, remainder); + maxp = pkt->maxp; + send = pkt->actual; + remainder = pkt->length; /* - * send < 0 : pipe busy * send = 0 : send zero packet * send > 0 : send data * * send <= max_packet */ - if (send > 0) - req->actual += send; + req->actual += send; /* send all packet ? */ if (send < remainder) @@ -372,13 +371,6 @@ static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep, uep->handler->irq_mask(uep, enable); /* - * usbhs_fifo_enable execute - * - after callback_update, - * - before queue_pop / stage_end - */ - usbhs_pipe_enable(pipe); - - /* * all data were sent ? */ if (is_done) { @@ -389,6 +381,30 @@ static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep, usbhsg_queue_pop(uep, ureq, 0); } +} + +static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep, + struct usbhsg_request *ureq) +{ + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usb_request *req = &ureq->req; + struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); + int ret; + + /* + ********* assume under spin lock ********* + */ + + usbhs_pkt_update(pkt, pipe, + req->buf + req->actual, + req->length - req->actual); + + ret = usbhs_fifo_write(pkt); + if (ret < 0) { + /* pipe is busy. + * retry in interrupt */ + uep->handler->irq_mask(uep, 1); + } return 0; } @@ -408,35 +424,30 @@ static int usbhsg_prepare_send_packet(struct usbhsg_uep *uep, return 0; } -static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) +/* + * packet recv hander + */ +static void usbhsg_try_run_receive_packet_bh(struct usbhs_pkt *pkt) { - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); + struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); - void *buf; - int maxp; - int remainder, recv; + int remainder, recv, maxp; int is_done = 0; - /* - ********* assume under spin lock ********* - */ - - maxp = usbhs_pipe_get_maxpacket(pipe); - buf = req->buf + req->actual; - remainder = req->length - req->actual; + maxp = pkt->maxp; + remainder = pkt->length; + recv = pkt->actual; - recv = usbhs_fifo_read(pipe, buf, remainder); /* * recv < 0 : pipe busy * recv >= 0 : receive data * * recv <= max_packet */ - if (recv < 0) - return -EBUSY; /* update parameters */ req->actual += recv; @@ -457,8 +468,24 @@ static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep, usbhs_pipe_disable(pipe); usbhsg_queue_pop(uep, ureq, 0); } +} - return 0; +static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep, + struct usbhsg_request *ureq) +{ + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usb_request *req = &ureq->req; + struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); + + /* + ********* assume under spin lock ********* + */ + + usbhs_pkt_update(pkt, pipe, + req->buf + req->actual, + req->length - req->actual); + + return usbhs_fifo_read(pkt); } static int usbhsg_prepare_receive_packet(struct usbhsg_uep *uep, @@ -1086,7 +1113,9 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) /* * pipe initialize and enable DCP */ - usbhs_pipe_init(priv); + usbhs_pipe_init(priv, + usbhsg_try_run_send_packet_bh, + usbhsg_try_run_receive_packet_bh); usbhsg_uep_init(gpriv); usbhsg_dcp_enable(dcp); diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 75e9e3cbc0e5..7a11616d6e28 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -531,7 +531,9 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) return pipe; } -void usbhs_pipe_init(struct usbhs_priv *priv) +void usbhs_pipe_init(struct usbhs_priv *priv, + void (*tx_done)(struct usbhs_pkt *pkt), + void (*rx_done)(struct usbhs_pkt *pkt)) { struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct usbhs_pipe *pipe; @@ -561,6 +563,9 @@ void usbhs_pipe_init(struct usbhs_priv *priv) usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); usbhsp_pipectrl_set(pipe, ACLRM, 0); } + + info->tx_done = tx_done; + info->rx_done = rx_done; } struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, @@ -639,7 +644,6 @@ void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) usbhsp_pipectrl_set(pipe, CCPL, CCPL); } - /* * pipe module function */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 2fb69df932ed..1f871b0c4971 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -18,6 +18,7 @@ #define RENESAS_USB_PIPE_H #include "./common.h" +#include "./fifo.h" /* * struct @@ -39,6 +40,9 @@ struct usbhs_pipe_info { struct usbhs_pipe *pipe; int size; /* array size of "pipe" */ int bufnmb_last; /* FIXME : driver needs good allocator */ + + void (*tx_done)(struct usbhs_pkt *pkt); + void (*rx_done)(struct usbhs_pkt *pkt); }; /* @@ -76,7 +80,9 @@ int usbhs_pipe_probe(struct usbhs_priv *priv); void usbhs_pipe_remove(struct usbhs_priv *priv); int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); -void usbhs_pipe_init(struct usbhs_priv *priv); +void usbhs_pipe_init(struct usbhs_priv *priv, + void (*tx_done)(struct usbhs_pkt *pkt), + void (*rx_done)(struct usbhs_pkt *pkt)); int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); |