aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/renesas_usbhs/mod_host.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod_host.c')
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 1834cf50888..10e1ded9c9c 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -85,6 +85,7 @@ struct usbhsh_ep {
struct usbhsh_device *udev; /* attached udev */
struct usb_host_endpoint *ep;
struct list_head ep_list; /* list to usbhsh_device */
+ unsigned int counter; /* pipe attach counter */
};
#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
@@ -110,9 +111,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
#define __usbhsh_for_each_udev(start, pos, h, i) \
- for (i = start, pos = (h)->udev + i; \
- i < USBHSH_DEVICE_MAX; \
- i++, pos = (h)->udev + i)
+ for ((i) = start; \
+ ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i)); \
+ (i)++)
#define usbhsh_for_each_udev(pos, hpriv, i) \
__usbhsh_for_each_udev(1, pos, hpriv, i)
@@ -271,8 +272,12 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
/******************** spin lock ********************/
usbhs_lock(priv, flags);
- if (unlikely(usbhsh_uep_to_pipe(uep))) {
- dev_err(dev, "uep already has pipe\n");
+ /*
+ * if uep has been attached to pipe,
+ * reuse it
+ */
+ if (usbhsh_uep_to_pipe(uep)) {
+ ret = 0;
goto usbhsh_pipe_attach_done;
}
@@ -320,6 +325,9 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
}
usbhsh_pipe_attach_done:
+ if (0 == ret)
+ uep->counter++;
+
usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
@@ -334,6 +342,11 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
struct device *dev = usbhs_priv_to_dev(priv);
unsigned long flags;
+ if (unlikely(!uep)) {
+ dev_err(dev, "no uep\n");
+ return;
+ }
+
/******************** spin lock ********************/
usbhs_lock(priv, flags);
@@ -341,7 +354,7 @@ static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
if (unlikely(!pipe)) {
dev_err(dev, "uep doens't have pipe\n");
- } else {
+ } else if (1 == uep->counter--) { /* last user */
struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep);
struct usbhsh_device *udev = usbhsh_uep_to_udev(uep);
@@ -386,6 +399,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv,
/*
* init endpoint
*/
+ uep->counter = 0;
INIT_LIST_HEAD(&uep->ep_list);
list_add_tail(&uep->ep_list, &udev->ep_list_head);
@@ -647,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
status = -ESHUTDOWN;
urb->actual_length = pkt->actual;
- usbhsh_ureq_free(hpriv, ureq);
usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
+ usbhsh_ureq_free(hpriv, ureq);
+
usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
usb_hcd_unlink_urb_from_ep(hcd, urb);
@@ -681,9 +696,9 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
}
if (usb_pipein(urb->pipe))
- pipe->handler = &usbhs_fifo_pio_pop_handler;
+ pipe->handler = &usbhs_fifo_dma_pop_handler;
else
- pipe->handler = &usbhs_fifo_pio_push_handler;
+ pipe->handler = &usbhs_fifo_dma_push_handler;
buf = (void *)(urb->transfer_buffer + urb->actual_length);
len = urb->transfer_buffer_length - urb->actual_length;
@@ -916,6 +931,19 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
*/
static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
{
+ if (map) {
+ struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
+ struct urb *urb = ureq->urb;
+
+ /* it can not use scatter/gather */
+ if (urb->num_sgs)
+ return -EINVAL;
+
+ pkt->dma = urb->transfer_dma;
+ if (!pkt->dma)
+ return -EINVAL;
+ }
+
return 0;
}
@@ -941,7 +969,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *ep = urb->ep;
struct usbhsh_device *new_udev = NULL;
int is_dir_in = usb_pipein(urb->pipe);
- int i;
int ret;
dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out");
@@ -987,13 +1014,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
* attach pipe to endpoint
* see [image of mod_host]
*/
- for (i = 0; i < 1024; i++) {
- ret = usbhsh_pipe_attach(hpriv, urb);
- if (ret < 0)
- msleep(100);
- else
- break;
- }
+ ret = usbhsh_pipe_attach(hpriv, urb);
if (ret < 0) {
dev_err(dev, "pipe attach failed\n");
goto usbhsh_urb_enqueue_error_free_endpoint;
@@ -1067,8 +1088,6 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,
static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
- struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
- struct device *dev = usbhs_priv_to_dev(priv);
int roothub_id = 1; /* only 1 root hub */
/*
@@ -1080,8 +1099,6 @@ static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
else
*buf = 0;
- dev_dbg(dev, "%s (%02x)\n", __func__, *buf);
-
return !!(*buf);
}
@@ -1266,6 +1283,12 @@ static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return ret;
}
+static int usbhsh_bus_nop(struct usb_hcd *hcd)
+{
+ /* nothing to do */
+ return 0;
+}
+
static struct hc_driver usbhsh_driver = {
.description = usbhsh_hcd_name,
.hcd_priv_size = sizeof(struct usbhsh_hpriv),
@@ -1290,6 +1313,8 @@ static struct hc_driver usbhsh_driver = {
*/
.hub_status_data = usbhsh_hub_status_data,
.hub_control = usbhsh_hub_control,
+ .bus_suspend = usbhsh_bus_nop,
+ .bus_resume = usbhsh_bus_nop,
};
/*
@@ -1444,6 +1469,7 @@ static int usbhsh_start(struct usbhs_priv *priv)
ret = usb_add_hcd(hcd, 0, 0);
if (ret < 0)
return 0;
+ device_wakeup_enable(hcd->self.controller);
/*
* pipe initialize and enable DCP