diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod_host.c')
| -rw-r--r-- | drivers/usb/renesas_usbhs/mod_host.c | 68 |
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 |
