From 7bb4fdc602c6cc763185d88f58ed75c84eb32158 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 10 Oct 2011 18:38:09 +0200 Subject: [PATCH 01/50] USB: ci13xxx_udc: make suspend and resume in gadget driver optional Some gadget drivers don't implement suspend and/or resume functions. Instead of changing the gadget drivers, make suspend and resume in ci13xxx_udc (following other udc drivers) optional. Tested-by: Pavankumar Kondeti Signed-off-by: Marc Kleine-Budde Signed-off-by: Felipe Balbi --- drivers/usb/gadget/ci13xxx_udc.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 9a0c3979ff43..9db7e7667c2b 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -2563,9 +2563,7 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, if (driver == NULL || bind == NULL || driver->setup == NULL || - driver->disconnect == NULL || - driver->suspend == NULL || - driver->resume == NULL) + driver->disconnect == NULL) return -EINVAL; else if (udc == NULL) return -ENODEV; @@ -2693,8 +2691,6 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver) driver->unbind == NULL || driver->setup == NULL || driver->disconnect == NULL || - driver->suspend == NULL || - driver->resume == NULL || driver != udc->driver) return -EINVAL; @@ -2793,7 +2789,7 @@ static irqreturn_t udc_irq(void) isr_statistics.pci++; udc->gadget.speed = hw_port_is_high_speed() ? USB_SPEED_HIGH : USB_SPEED_FULL; - if (udc->suspended) { + if (udc->suspended && udc->driver->resume) { spin_unlock(udc->lock); udc->driver->resume(&udc->gadget); spin_lock(udc->lock); @@ -2807,7 +2803,8 @@ static irqreturn_t udc_irq(void) isr_tr_complete_handler(udc); } if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN && + udc->driver->suspend) { udc->suspended = 1; spin_unlock(udc->lock); udc->driver->suspend(&udc->gadget); From dd39c358dff41394f20b623fc68be857b6d702ad Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 10 Oct 2011 18:38:10 +0200 Subject: [PATCH 02/50] USB: ci13xxx_udc: handle controllers with less than 16 EPs The ci13xxx_udc driver checks the number of endpoints in the udc controller, however some routines expect that the hardware has 16 bidirectional endpoints. This patch improves the driver to work on controllers with less than 16 endpoints like the udc controller found on freescale's mx23 and mx28. Tested-by: Pavankumar Kondeti Signed-off-by: Marc Kleine-Budde Signed-off-by: Felipe Balbi --- drivers/usb/gadget/ci13xxx_udc.c | 16 ++++++++++++++-- drivers/usb/gadget/ci13xxx_udc.h | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 9db7e7667c2b..8956a2448b33 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -182,6 +182,16 @@ static inline int hw_ep_bit(int num, int dir) return num + (dir ? 16 : 0); } +static int ep_to_bit(int n) +{ + int fill = 16 - hw_ep_max / 2; + + if (n >= hw_ep_max / 2) + n += fill; + + return n; +} + /** * hw_aread: reads from register bitfield * @addr: address relative to bus map @@ -440,12 +450,13 @@ static int hw_ep_get_halt(int num, int dir) /** * hw_test_and_clear_setup_status: test & clear setup status (execute without * interruption) - * @n: bit number (endpoint) + * @n: endpoint number * * This function returns setup status */ static int hw_test_and_clear_setup_status(int n) { + n = ep_to_bit(n); return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); } @@ -641,12 +652,13 @@ static int hw_register_write(u16 addr, u32 data) /** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) - * @n: bit number (endpoint) + * @n: endpoint number * * This function returns complete status */ static int hw_test_and_clear_complete(int n) { + n = ep_to_bit(n); return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); } diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h index 23707775cb43..f4871e1fac59 100644 --- a/drivers/usb/gadget/ci13xxx_udc.h +++ b/drivers/usb/gadget/ci13xxx_udc.h @@ -127,7 +127,7 @@ struct ci13xxx { struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ u32 ep0_dir; /* ep0 direction */ #define ep0out ci13xxx_ep[0] -#define ep0in ci13xxx_ep[16] +#define ep0in ci13xxx_ep[hw_ep_max / 2] u8 remote_wakeup; /* Is remote wakeup feature enabled by the host? */ u8 suspended; /* suspended by the host */ From 2288e109931577582f09d6295029bbf098c6f939 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:55:47 -0700 Subject: [PATCH 03/50] usb: gadget: renesas_usbhs: remove usbhs_sys_hispeed_ctrl() usbhs_sys_hispeed_ctrl() can collect into usbhs_sys_host/function_ctrl(). Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 13 ++++--------- drivers/usb/renesas_usbhs/common.h | 1 - drivers/usb/renesas_usbhs/mod_gadget.c | 2 -- drivers/usb/renesas_usbhs/mod_host.c | 2 -- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 08c679c0dde5..38249da8e7b2 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -100,11 +100,6 @@ void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0); } -void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable) -{ - usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0); -} - void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable) { usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0); @@ -112,8 +107,8 @@ void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable) void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) { - u16 mask = DCFM | DRPD | DPRPU; - u16 val = DCFM | DRPD; + u16 mask = DCFM | DRPD | DPRPU | HSE; + u16 val = DCFM | DRPD | HSE; int has_otg = usbhs_get_dparam(priv, has_otg); if (has_otg) @@ -130,8 +125,8 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) { - u16 mask = DCFM | DRPD | DPRPU; - u16 val = DPRPU; + u16 mask = DCFM | DRPD | DPRPU | HSE; + u16 val = DPRPU | HSE; /* * if enable diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 8729da5c3be6..30d1887fda99 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -284,7 +284,6 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); * sysconfig */ void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 7f4e80338570..f23839ddd62c 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -681,7 +681,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) * - function * - usb module */ - usbhs_sys_hispeed_ctrl(priv, 1); usbhs_sys_function_ctrl(priv, 1); usbhs_sys_usb_ctrl(priv, 1); @@ -731,7 +730,6 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) gpriv->gadget.speed = USB_SPEED_UNKNOWN; /* disable sys */ - usbhs_sys_hispeed_ctrl(priv, 0); usbhs_sys_function_ctrl(priv, 0); usbhs_sys_usb_ctrl(priv, 0); diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index bade761a1e52..366a8a79fd56 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1205,7 +1205,6 @@ static int usbhsh_start(struct usbhs_priv *priv) * - host * - usb module */ - usbhs_sys_hispeed_ctrl(priv, 1); usbhs_sys_host_ctrl(priv, 1); usbhs_sys_usb_ctrl(priv, 1); @@ -1242,7 +1241,6 @@ static int usbhsh_stop(struct usbhs_priv *priv) usb_remove_hcd(hcd); /* disable sys */ - usbhs_sys_hispeed_ctrl(priv, 0); usbhs_sys_host_ctrl(priv, 0); usbhs_sys_usb_ctrl(priv, 0); From 3244a7b43f13682c3323ee0d781f0cb212e8b3e7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:56:30 -0700 Subject: [PATCH 04/50] usb: gadget: renesas_usbhs: remove usbhs_sys_usb_ctrl() usbhs_sys_usb_ctrl() can collect into usbhs_sys_host/function_ctrl(). Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 13 ++++--------- drivers/usb/renesas_usbhs/common.h | 1 - drivers/usb/renesas_usbhs/mod_gadget.c | 2 -- drivers/usb/renesas_usbhs/mod_host.c | 2 -- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 38249da8e7b2..ce54abfde006 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -100,15 +100,10 @@ void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0); } -void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable) -{ - usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0); -} - void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) { - u16 mask = DCFM | DRPD | DPRPU | HSE; - u16 val = DCFM | DRPD | HSE; + u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; + u16 val = DCFM | DRPD | HSE | USBE; int has_otg = usbhs_get_dparam(priv, has_otg); if (has_otg) @@ -125,8 +120,8 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) { - u16 mask = DCFM | DRPD | DPRPU | HSE; - u16 val = DPRPU | HSE; + u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; + u16 val = DPRPU | HSE | USBE; /* * if enable diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 30d1887fda99..46c9fd2f30ed 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -284,7 +284,6 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); * sysconfig */ void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index f23839ddd62c..8fb9056ff48d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -682,7 +682,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) * - usb module */ usbhs_sys_function_ctrl(priv, 1); - usbhs_sys_usb_ctrl(priv, 1); /* * enable irq callback @@ -731,7 +730,6 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) /* disable sys */ usbhs_sys_function_ctrl(priv, 0); - usbhs_sys_usb_ctrl(priv, 0); usbhsg_pipe_disable(dcp); diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 366a8a79fd56..2656d5989e68 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1206,7 +1206,6 @@ static int usbhsh_start(struct usbhs_priv *priv) * - usb module */ usbhs_sys_host_ctrl(priv, 1); - usbhs_sys_usb_ctrl(priv, 1); /* * enable irq callback @@ -1242,7 +1241,6 @@ static int usbhsh_stop(struct usbhs_priv *priv) /* disable sys */ usbhs_sys_host_ctrl(priv, 0); - usbhs_sys_usb_ctrl(priv, 0); dev_dbg(dev, "quit host\n"); From 76190152fb62650ea6530c166d9adbaa08cdb5d0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:56:41 -0700 Subject: [PATCH 05/50] usb: gadget: renesas_usbhs: tidyup usbhs_sys_clock_ctrl() was local function Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 2 +- drivers/usb/renesas_usbhs/common.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index ce54abfde006..1ce32d92e720 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -95,7 +95,7 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev) /* * syscfg functions */ -void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) +static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) { usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0); } diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 46c9fd2f30ed..3199d3799045 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -283,7 +283,6 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); /* * sysconfig */ -void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); From 25234b46be2a1688d38fb55ed9d7e3f2cc41c9af Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:56:53 -0700 Subject: [PATCH 06/50] usb: gadget: renesas_usbhs: tidyup mod_host request variable name renesas_usbhs driver use "req" for struct usb_ctrlrequest, and "ureq" for struct usbhsh_request Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 2656d5989e68..c453b6c215a7 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -170,19 +170,19 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s)) #define usbhsh_port_stat_get(h) ((h)->port_stat) -#define usbhsh_pkt_to_req(p) \ +#define usbhsh_pkt_to_ureq(p) \ container_of((void *)p, struct usbhsh_request, pkt) /* * req alloc/free */ -static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv) +static void usbhsh_ureq_list_init(struct usbhsh_hpriv *hpriv) { INIT_LIST_HEAD(&hpriv->ureq_link_active); INIT_LIST_HEAD(&hpriv->ureq_link_free); } -static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) +static void usbhsh_ureq_list_quit(struct usbhsh_hpriv *hpriv) { struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct device *dev = usbhsh_hcd_to_dev(hcd); @@ -201,7 +201,7 @@ static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) kfree(ureq); } -static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, +static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, struct urb *urb, gfp_t mem_flags) { @@ -243,7 +243,7 @@ static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, return ureq; } -static void usbhsh_req_free(struct usbhsh_hpriv *hpriv, +static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, struct usbhsh_request *ureq) { struct usbhs_pkt *pkt = &ureq->pkt; @@ -480,7 +480,7 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, */ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { - struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); + struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct urb *urb = ureq->urb; @@ -494,7 +494,7 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) } urb->actual_length = pkt->actual; - usbhsh_req_free(hpriv, ureq); + usbhsh_ureq_free(hpriv, ureq); usbhsh_urb_to_ureq(urb) = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); @@ -537,12 +537,12 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, */ static int usbhsh_is_request_address(struct urb *urb) { - struct usb_ctrlrequest *cmd; + struct usb_ctrlrequest *req; - cmd = (struct usb_ctrlrequest *)urb->setup_packet; + req = (struct usb_ctrlrequest *)urb->setup_packet; - if ((DeviceOutRequest == cmd->bRequestType << 8) && - (USB_REQ_SET_ADDRESS == cmd->bRequest)) + if ((DeviceOutRequest == req->bRequestType << 8) && + (USB_REQ_SET_ADDRESS == req->bRequest)) return 1; else return 0; @@ -595,13 +595,13 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { - struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); + struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct urb *urb = ureq->urb; /* this ureq was connected to urb when usbhsh_urb_enqueue() */ - usbhsh_req_free(hpriv, ureq); + usbhsh_ureq_free(hpriv, ureq); usbhsh_urb_to_ureq(urb) = NULL; } @@ -650,7 +650,7 @@ static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, * status stage uses allocated ureq. * it will be freed on usbhsh_queue_done() */ - ureq = usbhsh_req_alloc(hpriv, urb, GFP_KERNEL); + ureq = usbhsh_ureq_alloc(hpriv, urb, GFP_KERNEL); pkt = &ureq->pkt; if (usb_pipein(urb->pipe)) @@ -772,7 +772,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, /* * alloc new request */ - ureq = usbhsh_req_alloc(hpriv, urb, mem_flags); + ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); if (unlikely(!ureq)) { ret = -ENOMEM; goto usbhsh_urb_enqueue_error_free_endpoint; @@ -807,7 +807,7 @@ static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); if (ureq) { - usbhsh_req_free(hpriv, ureq); + usbhsh_ureq_free(hpriv, ureq); usbhsh_urb_to_ureq(urb) = NULL; } @@ -1291,7 +1291,7 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) hpriv->mod.stop = usbhsh_stop; hpriv->pipe_info = pipe_info; hpriv->pipe_size = pipe_size; - usbhsh_req_list_init(hpriv); + usbhsh_ureq_list_init(hpriv); usbhsh_port_stat_init(hpriv); /* init all device */ @@ -1315,7 +1315,7 @@ int usbhs_mod_host_remove(struct usbhs_priv *priv) struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - usbhsh_req_list_quit(hpriv); + usbhsh_ureq_list_quit(hpriv); usb_put_hcd(hcd); From a49a88f108516fd5ae24e26df5a63beb847807df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:57:02 -0700 Subject: [PATCH 07/50] usb: gadget: renesas_usbhs: tidyup the unit of detection_delay detection_delay was assumed as msec Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 3 ++- include/linux/usb/renesas_usbhs.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 1ce32d92e720..b4cf555ce58e 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -388,7 +388,8 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) * To make sure safety context, * use workqueue for usbhs_notify_hotplug */ - schedule_delayed_work(&priv->notify_hotplug_work, delay); + schedule_delayed_work(&priv->notify_hotplug_work, + msecs_to_jiffies(delay)); return 0; } diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index e5a40c318548..c9fceb9f7690 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -118,7 +118,7 @@ struct renesas_usbhs_driver_param { * * delay time from notify_hotplug callback */ - int detection_delay; + int detection_delay; /* msec */ /* * option: From f1ee56a0004c4a5974e7a69665330b6ff818bf92 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 23 Oct 2011 19:57:10 -0700 Subject: [PATCH 08/50] usb: gadget: renesas_usbhs: add platform power control function Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 7 +++++++ include/linux/usb/renesas_usbhs.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b4cf555ce58e..17bf1f74377a 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -291,18 +291,25 @@ static u32 usbhsc_default_pipe_type[] = { */ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) { + struct platform_device *pdev = usbhs_priv_to_pdev(priv); struct device *dev = usbhs_priv_to_dev(priv); if (enable) { /* enable PM */ pm_runtime_get_sync(dev); + /* enable platform power */ + usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* USB on */ usbhs_sys_clock_ctrl(priv, enable); } else { /* USB off */ usbhs_sys_clock_ctrl(priv, enable); + /* disable platform power */ + usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); + /* disable PM */ pm_runtime_put_sync(dev); } diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index c9fceb9f7690..0d3f98879256 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -64,6 +64,14 @@ struct renesas_usbhs_platform_callback { */ void (*hardware_exit)(struct platform_device *pdev); + /* + * option: + * + * for board specific clock control + */ + void (*power_ctrl)(struct platform_device *pdev, + void __iomem *base, int enable); + /* * option: * From b4fcea2a71cafc59a749fa3ef88e51af8c2e3b37 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 24 Oct 2011 02:25:48 -0700 Subject: [PATCH 09/50] usb: gadget: renesas_usbhs: unified callback function renesas_usbhs needs callback for notify hotplug. but it were 2 methods which are almost same. This patch unified these into one. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 2 +- drivers/usb/renesas_usbhs/common.h | 2 -- drivers/usb/renesas_usbhs/mod.c | 4 +++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 17bf1f74377a..0fea6b63ccce 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -385,7 +385,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work) usbhsc_hotplug(priv); } -int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) +static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); int delay = usbhs_get_dparam(priv, detection_delay); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 3199d3799045..e255015072a6 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -275,8 +275,6 @@ u16 usbhs_read(struct usbhs_priv *priv, u32 reg); void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data); void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); -int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); - #define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f) #define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f) diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 053f86d70009..f382e4314362 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -50,7 +50,9 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, { struct platform_device *pdev = usbhs_priv_to_pdev(priv); - return usbhsc_drvcllbck_notify_hotplug(pdev); + renesas_usbhs_call_notify_hotplug(pdev); + + return 0; } void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) From 144974e7f9e32b53b02f6c8632be45d8f43d6ab5 Mon Sep 17 00:00:00 2001 From: Yuping Luo Date: Tue, 25 Oct 2011 19:13:10 -0700 Subject: [PATCH 10/50] usb: gadget: mass_storage: support multi-luns with different logic block size With Peiyu's patch "gadget: mass_storage: adapt logic block size to bound block devices" (http://www.spinics.net/lists/linux-usb/msg50791.html), now mass storage can adjust logic block size dynamically based on real devices. Then there is one issue caused by it, if two luns have different logic block size, mass storage can't work. Let's check the current software flow: 1. get_next_command(): call received_cbw(); 2. received_cbw(): update common->lun = cbw->Lun, but common->curlen is not updated; 3. do_scsi_command(): in READ_X and WRITE_X commands, common->data_size_from_cmnd is updated by common->curlun->blkbits; 4. check_command(): update common->curlun according to common->lun As you can see, the step 3 uses wrong common->curlun, then wrong common->curlun->blkbits. If the two luns have same blkbits, there isn't issue. Otherwise, both will fail. This patch moves the common->curlun update to step 1, then make sure step 3 gets right blkbits and data_size_from_cmnd. Cc: Peiyu Li Signed-off-by: YuPing Luo Signed-off-by: Barry Song Acked-by: Alan Stern Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 58 ++++++++++++++++----------- drivers/usb/gadget/file_storage.c | 62 +++++++++++++++++++---------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index c39d58860fa0..860e15ac8f24 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1873,17 +1873,14 @@ static int check_command(struct fsg_common *common, int cmnd_size, common->lun, lun); /* Check the LUN */ - if (common->lun < common->nluns) { - curlun = &common->luns[common->lun]; - common->curlun = curlun; + curlun = common->curlun; + if (curlun) { if (common->cmnd[0] != REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } } else { - common->curlun = NULL; - curlun = NULL; common->bad_lun_okay = 0; /* @@ -1929,6 +1926,17 @@ static int check_command(struct fsg_common *common, int cmnd_size, return 0; } +/* wrapper of check_command for data size in blocks handling */ +static int check_command_size_in_blocks(struct fsg_common *common, + int cmnd_size, enum data_direction data_dir, + unsigned int mask, int needs_medium, const char *name) +{ + if (common->curlun) + common->data_size_from_cmnd <<= common->curlun->blkbits; + return check_command(common, cmnd_size, data_dir, + mask, needs_medium, name); +} + static int do_scsi_command(struct fsg_common *common) { struct fsg_buffhd *bh; @@ -2011,9 +2019,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << - common->curlun->blkbits; - reply = check_command(common, 6, DATA_DIR_TO_HOST, + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)"); if (reply == 0) @@ -2022,9 +2030,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << - common->curlun->blkbits; - reply = check_command(common, 10, DATA_DIR_TO_HOST, + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)"); if (reply == 0) @@ -2033,9 +2041,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << - common->curlun->blkbits; - reply = check_command(common, 12, DATA_DIR_TO_HOST, + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)"); if (reply == 0) @@ -2134,9 +2142,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << - common->curlun->blkbits; - reply = check_command(common, 6, DATA_DIR_FROM_HOST, + common->data_size_from_cmnd = (i == 0) ? 256 : i; + reply = check_command_size_in_blocks(common, 6, + DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)"); if (reply == 0) @@ -2145,9 +2153,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << - common->curlun->blkbits; - reply = check_command(common, 10, DATA_DIR_FROM_HOST, + get_unaligned_be16(&common->cmnd[7]); + reply = check_command_size_in_blocks(common, 10, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)"); if (reply == 0) @@ -2156,9 +2164,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << - common->curlun->blkbits; - reply = check_command(common, 12, DATA_DIR_FROM_HOST, + get_unaligned_be32(&common->cmnd[6]); + reply = check_command_size_in_blocks(common, 12, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)"); if (reply == 0) @@ -2273,6 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; + if (common->lun >= 0 && common->lun < common->nluns) + common->curlun = &common->luns[common->lun]; + else + common->curlun = NULL; common->tag = cbw->Tag; return 0; } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 11b5196284ae..e8ff2f1c06cc 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, DBG(fsg, "using LUN %d from CBW, " "not LUN %d from CDB\n", fsg->lun, lun); - } else - fsg->lun = lun; // Use LUN from the command + } /* Check the LUN */ - if (fsg->lun < fsg->nluns) { - fsg->curlun = curlun = &fsg->luns[fsg->lun]; + curlun = fsg->curlun; + if (curlun) { if (fsg->cmnd[0] != REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; curlun->info_valid = 0; } } else { - fsg->curlun = curlun = NULL; fsg->bad_lun_okay = 0; /* INQUIRY and REQUEST SENSE commands are explicitly allowed @@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, return 0; } +/* wrapper of check_command for data size in blocks handling */ +static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, + enum data_direction data_dir, unsigned int mask, + int needs_medium, const char *name) +{ + if (fsg->curlun) + fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; + return check_command(fsg, cmnd_size, data_dir, + mask, needs_medium, name); +} static int do_scsi_command(struct fsg_dev *fsg) { @@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = (i == 0) ? 256 : i; + if ((reply = check_command_size_in_blocks(fsg, 6, + DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)")) == 0) reply = do_read(fsg); break; case READ_10: - fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); + if ((reply = check_command_size_in_blocks(fsg, 10, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)")) == 0) reply = do_read(fsg); break; case READ_12: - fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); + if ((reply = check_command_size_in_blocks(fsg, 12, + DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) reply = do_read(fsg); @@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = (i == 0) ? 256 : i; + if ((reply = check_command_size_in_blocks(fsg, 6, + DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)")) == 0) reply = do_write(fsg); break; case WRITE_10: - fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); + if ((reply = check_command_size_in_blocks(fsg, 10, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)")) == 0) reply = do_write(fsg); break; case WRITE_12: - fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; - if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); + if ((reply = check_command_size_in_blocks(fsg, 12, + DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) reply = do_write(fsg); @@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg) memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); fsg->cbbuf_cmnd_size = 0; spin_unlock_irq(&fsg->lock); + + /* Use LUN from the command */ + fsg->lun = fsg->cmnd[1] >> 5; } + + /* Update current lun */ + if (fsg->lun >= 0 && fsg->lun < fsg->nluns) + fsg->curlun = &fsg->luns[fsg->lun]; + else + fsg->curlun = NULL; + return rc; } From 1ab6f257e12a89f62f58fcef9f7b85badce412bc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:46:36 -0700 Subject: [PATCH 11/50] usb: gadget: renesas_usbhs: drop dependency for mod_gadget Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 23a447373c51..953b00cd59ff 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -234,7 +234,6 @@ config USB_R8A66597 config USB_RENESAS_USBHS_UDC tristate 'Renesas USBHS controller' - depends on SUPERH || ARCH_SHMOBILE depends on USB_RENESAS_USBHS select USB_GADGET_DUALSPEED help From ee8a0bf5a775098b1140195b6bfacb4813166e5f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:46:50 -0700 Subject: [PATCH 12/50] usb: gadget: renesas_usbhs: cleanup complicated ureq alloc/free DCP data/status stage needs ureq to usbhs_pkt_push(), but sometimes, there is no data stage. In that case, allocated ureq was not freed, Current ureq alloc/free pair were difficult to understand. This patch removed unnecessary/un-understandable ureq alloc from usbhsh_urb_enqueue(), and create simpler alloc/free pair. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 107 ++++++++++++++------------- 1 file changed, 56 insertions(+), 51 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index c453b6c215a7..478366b571ef 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -503,11 +503,12 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) static int usbhsh_queue_push(struct usb_hcd *hcd, struct usbhs_pipe *pipe, - struct urb *urb) + struct urb *urb, + gfp_t mem_flags) { - struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); - struct usbhs_pkt *pkt = &ureq->pkt; + struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); struct device *dev = usbhsh_hcd_to_dev(hcd); + struct usbhsh_request *ureq; void *buf; int len; @@ -516,6 +517,14 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, return -EIO; } + /* this ureq will be freed on usbhsh_queue_done() */ + ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); + if (unlikely(!ureq)) { + dev_err(dev, "ureq alloc fail\n"); + return -ENOMEM; + } + usbhsh_urb_to_ureq(urb) = ureq; + if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_fifo_pio_pop_handler; else @@ -525,7 +534,7 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, len = urb->transfer_buffer_length - urb->actual_length; dev_dbg(dev, "%s\n", __func__); - usbhs_pkt_push(pipe, pkt, usbhsh_queue_done, + usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); usbhs_pkt_start(pipe); @@ -605,72 +614,72 @@ static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, usbhsh_urb_to_ureq(urb) = NULL; } -static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pipe *pipe) +static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, + struct urb *urb, + struct usbhs_pipe *pipe, + gfp_t mem_flags) + { struct usbhsh_request *ureq; - struct usbhs_pkt *pkt; - /* - * FIXME - * - * data stage uses ureq which is connected to urb - * see usbhsh_urb_enqueue() :: alloc new request. - * it will be freed in usbhsh_data_stage_packet_done() - */ - ureq = usbhsh_urb_to_ureq(urb); - pkt = &ureq->pkt; + /* this ureq will be freed on usbhsh_data_stage_packet_done() */ + ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); + if (unlikely(!ureq)) + return -ENOMEM; + usbhsh_urb_to_ureq(urb) = ureq; if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_dcp_data_stage_in_handler; else pipe->handler = &usbhs_dcp_data_stage_out_handler; - usbhs_pkt_push(pipe, pkt, + usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_data_stage_packet_done, urb->transfer_buffer, urb->transfer_buffer_length, (urb->transfer_flags & URB_ZERO_PACKET)); + + return 0; } /* * DCP status stage */ -static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, +static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, struct urb *urb, - struct usbhs_pipe *pipe) + struct usbhs_pipe *pipe, + gfp_t mem_flags) { struct usbhsh_request *ureq; - struct usbhs_pkt *pkt; - /* - * FIXME - * - * status stage uses allocated ureq. - * it will be freed on usbhsh_queue_done() - */ - ureq = usbhsh_ureq_alloc(hpriv, urb, GFP_KERNEL); - pkt = &ureq->pkt; + /* This ureq will be freed on usbhsh_queue_done() */ + ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); + if (unlikely(!ureq)) + return -ENOMEM; + usbhsh_urb_to_ureq(urb) = ureq; if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_dcp_status_stage_in_handler; else pipe->handler = &usbhs_dcp_status_stage_out_handler; - usbhs_pkt_push(pipe, pkt, + usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, NULL, urb->transfer_buffer_length, 0); + + return 0; } static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, - struct usbhsh_hpriv *hpriv, struct usbhs_pipe *pipe, - struct urb *urb) + struct urb *urb, + gfp_t mflags) { + struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); struct device *dev = usbhsh_hcd_to_dev(hcd); + int ret; dev_dbg(dev, "%s\n", __func__); @@ -686,13 +695,22 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, * * It is pushed only when urb has buffer. */ - if (urb->transfer_buffer_length) - usbhsh_data_stage_packet_push(hpriv, urb, pipe); + if (urb->transfer_buffer_length) { + ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags); + if (ret < 0) { + dev_err(dev, "data stage failed\n"); + return ret; + } + } /* * status stage */ - usbhsh_status_stage_packet_push(hpriv, urb, pipe); + ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags); + if (ret < 0) { + dev_err(dev, "status stage failed\n"); + return ret; + } /* * start pushed packets @@ -731,7 +749,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct device *dev = usbhs_priv_to_dev(priv); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_request *ureq; struct usbhsh_device *udev, *new_udev = NULL; struct usbhs_pipe *pipe; struct usbhsh_ep *uep; @@ -769,28 +786,16 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, } pipe = usbhsh_uep_to_pipe(uep); - /* - * alloc new request - */ - ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); - if (unlikely(!ureq)) { - ret = -ENOMEM; - goto usbhsh_urb_enqueue_error_free_endpoint; - } - usbhsh_urb_to_ureq(urb) = ureq; - /* * push packet */ if (usb_pipecontrol(urb->pipe)) - usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb); + ret = usbhsh_dcp_queue_push(hcd, pipe, urb, mem_flags); else - usbhsh_queue_push(hcd, pipe, urb); + ret = usbhsh_queue_push(hcd, pipe, urb, mem_flags); - return 0; + return ret; -usbhsh_urb_enqueue_error_free_endpoint: - usbhsh_endpoint_free(hpriv, ep); usbhsh_urb_enqueue_error_free_device: if (new_udev) usbhsh_device_free(hpriv, new_udev); From fc9d5c79f681a7bff588d32de9429be360996df7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:47:01 -0700 Subject: [PATCH 13/50] usb: gadget: renesas_usbhs: usbhsh_ureq_alloc/free() care urb->hcpriv Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 478366b571ef..0b88e88c5ee6 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -239,6 +239,7 @@ static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, */ list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); ureq->urb = urb; + usbhsh_urb_to_ureq(urb) = ureq; return ureq; } @@ -254,6 +255,7 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, * removed from "active" list, * and push it to "free" list */ + usbhsh_urb_to_ureq(ureq->urb) = NULL; ureq->urb = NULL; list_del_init(&ureq->ureq_link); list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); @@ -495,7 +497,6 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) urb->actual_length = pkt->actual; usbhsh_ureq_free(hpriv, ureq); - usbhsh_urb_to_ureq(urb) = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); usb_hcd_giveback_urb(hcd, urb, 0); @@ -523,7 +524,6 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, dev_err(dev, "ureq alloc fail\n"); return -ENOMEM; } - usbhsh_urb_to_ureq(urb) = ureq; if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_fifo_pio_pop_handler; @@ -606,12 +606,10 @@ static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, { struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct urb *urb = ureq->urb; /* this ureq was connected to urb when usbhsh_urb_enqueue() */ usbhsh_ureq_free(hpriv, ureq); - usbhsh_urb_to_ureq(urb) = NULL; } static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, @@ -626,7 +624,6 @@ static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); if (unlikely(!ureq)) return -ENOMEM; - usbhsh_urb_to_ureq(urb) = ureq; if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_dcp_data_stage_in_handler; @@ -656,7 +653,6 @@ static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); if (unlikely(!ureq)) return -ENOMEM; - usbhsh_urb_to_ureq(urb) = ureq; if (usb_pipein(urb->pipe)) pipe->handler = &usbhs_dcp_status_stage_in_handler; @@ -811,10 +807,8 @@ static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); - if (ureq) { + if (ureq) usbhsh_ureq_free(hpriv, ureq); - usbhsh_urb_to_ureq(urb) = NULL; - } return 0; } From 3dd492686c063f9fa9417c3888e7a8eeb504b5b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:47:13 -0700 Subject: [PATCH 14/50] usb: gadget: renesas_usbhs: modify function name of usbhs_set_device_xx() it was device configuration setting function, not only speed. This patch modify function name usbhs_set_device_speed() -> usbhs_set_device_config() Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 2 +- drivers/usb/renesas_usbhs/common.h | 2 +- drivers/usb/renesas_usbhs/mod_host.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 0fea6b63ccce..016a34f58523 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -219,7 +219,7 @@ static void usbhsc_bus_init(struct usbhs_priv *priv) /* * device configuration */ -int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub, u16 hubport, u16 speed) { struct device *dev = usbhs_priv_to_dev(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index e255015072a6..71c295c76d9e 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -306,7 +306,7 @@ int usbhs_frame_get_num(struct usbhs_priv *priv); /* * device config */ -int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub, u16 hubport, u16 speed); /* diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 0b88e88c5ee6..7fa460e2a8c0 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -317,7 +317,7 @@ usbhsh_device_find: udev->usbv = usbv; /* set device config */ - usbhs_set_device_speed(priv, + usbhs_set_device_config(priv, usbhsh_device_number(hpriv, udev), usbhsh_device_number(hpriv, udev), 0, /* FIXME no parent */ @@ -433,7 +433,7 @@ usbhsh_endpoint_alloc_find_pipe: /* * usbhs_pipe_config_update() should be called after - * usbhs_device_config() + * usbhs_set_device_config() * see * DCPMAXP/PIPEMAXP */ From fca8ab7ee1c6d1857a4fcc9420cbf0e3b51aa199 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:47:24 -0700 Subject: [PATCH 15/50] usb: gadget: renesas_usbhs: cleanup usbhs_endpoint_disable() Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 7fa460e2a8c0..f18062c798a3 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -822,7 +822,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, /* * this function might be called manytimes by same hcd/ep - * in-endpoitn == out-endpoint if ep == dcp. + * in-endpoint == out-endpoint if ep == dcp. */ if (!uep) return; @@ -831,7 +831,6 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, hpriv = usbhsh_hcd_to_hpriv(hcd); usbhsh_endpoint_free(hpriv, ep); - ep->hcpriv = NULL; /* * if there is no endpoint, From 9c6736523a23371ae58c5427587ee1652ba059c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:47:34 -0700 Subject: [PATCH 16/50] usb: gadget: renesas_usbhs: usbhs_set_device_config() care upphub/hubport current usbhs_set_device_config() didn't care upphub/hubport. This patch adds its value. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index f18062c798a3..204f9f086846 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -161,6 +161,8 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_pipe_info(p) ((p)->mod_private) +#define usbhsh_device_parent(d) (usbhsh_usbv_to_udev((d)->usbv->parent)) +#define usbhsh_device_hubport(d) ((d)->usbv->portnum) #define usbhsh_device_number(h, d) ((int)((d) - (h)->udev)) #define usbhsh_device_nth(h, d) ((h)->udev + d) #define usbhsh_device0(h) usbhsh_device_nth(h, 0) @@ -264,6 +266,13 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, /* * device control */ +static int usbhsh_connected_to_rhdev(struct usb_hcd *hcd, + struct usbhsh_device *udev) +{ + struct usb_device *usbv = usbhsh_udev_to_usbv(udev); + + return hcd->self.root_hub == usbv->parent; +} static int usbhsh_device_has_endpoint(struct usbhsh_device *udev) { @@ -278,6 +287,7 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + u16 upphub, hubport; int i; /* @@ -316,12 +326,23 @@ usbhsh_device_find: dev_set_drvdata(&usbv->dev, udev); udev->usbv = usbv; + upphub = 0; + hubport = 0; + if (!usbhsh_connected_to_rhdev(hcd, udev)) { + /* if udev is not connected to rhdev, it means parent is Hub */ + struct usbhsh_device *parent = usbhsh_device_parent(udev); + + upphub = usbhsh_device_number(hpriv, parent); + hubport = usbhsh_device_hubport(udev); + + dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, + upphub, hubport, parent); + } + /* set device config */ usbhs_set_device_config(priv, usbhsh_device_number(hpriv, udev), - usbhsh_device_number(hpriv, udev), - 0, /* FIXME no parent */ - usbv->speed); + upphub, hubport, usbv->speed); dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); From c5b963f809f378d4fedd6f2f09b36f50c5a37bd5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:47:44 -0700 Subject: [PATCH 17/50] usb: gadget: renesas_usbhs: remove usbhsh_request list mod_host had usbhsh_request active/free list. it was almost meaningless, and vainly complicated. This patch remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 69 ++-------------------------- 1 file changed, 3 insertions(+), 66 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 204f9f086846..3f1eaf15e0ba 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -74,7 +74,6 @@ struct usbhsh_pipe_info { struct usbhsh_request { struct urb *urb; struct usbhs_pkt pkt; - struct list_head ureq_link; /* see hpriv :: ureq_link_xxx */ }; struct usbhsh_device { @@ -104,10 +103,6 @@ struct usbhsh_hpriv { u32 port_stat; /* USB_PORT_STAT_xxx */ struct completion setup_ack_done; - - /* see usbhsh_req_alloc/free */ - struct list_head ureq_link_active; - struct list_head ureq_link_free; }; @@ -178,31 +173,6 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; /* * req alloc/free */ -static void usbhsh_ureq_list_init(struct usbhsh_hpriv *hpriv) -{ - INIT_LIST_HEAD(&hpriv->ureq_link_active); - INIT_LIST_HEAD(&hpriv->ureq_link_free); -} - -static void usbhsh_ureq_list_quit(struct usbhsh_hpriv *hpriv) -{ - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct device *dev = usbhsh_hcd_to_dev(hcd); - struct usbhsh_request *ureq, *next; - - /* kfree all active ureq */ - list_for_each_entry_safe(ureq, next, - &hpriv->ureq_link_active, - ureq_link) { - dev_err(dev, "active ureq (%p) is force freed\n", ureq); - kfree(ureq); - } - - /* kfree all free ureq */ - list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link) - kfree(ureq); -} - static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, struct urb *urb, gfp_t mem_flags) @@ -211,35 +181,13 @@ static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); struct device *dev = usbhs_priv_to_dev(priv); - if (list_empty(&hpriv->ureq_link_free)) { - /* - * create new one if there is no free ureq - */ - ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); - if (ureq) - INIT_LIST_HEAD(&ureq->ureq_link); - } else { - /* - * reuse "free" ureq if exist - */ - ureq = list_entry(hpriv->ureq_link_free.next, - struct usbhsh_request, - ureq_link); - if (ureq) - list_del_init(&ureq->ureq_link); - } - + ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); if (!ureq) { dev_err(dev, "ureq alloc fail\n"); return NULL; } usbhs_pkt_init(&ureq->pkt); - - /* - * push it to "active" list - */ - list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); ureq->urb = urb; usbhsh_urb_to_ureq(urb) = ureq; @@ -249,18 +197,10 @@ static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, struct usbhsh_request *ureq) { - struct usbhs_pkt *pkt = &ureq->pkt; - - usbhs_pkt_init(pkt); - - /* - * removed from "active" list, - * and push it to "free" list - */ usbhsh_urb_to_ureq(ureq->urb) = NULL; ureq->urb = NULL; - list_del_init(&ureq->ureq_link); - list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); + + kfree(ureq); } /* @@ -1310,7 +1250,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) hpriv->mod.stop = usbhsh_stop; hpriv->pipe_info = pipe_info; hpriv->pipe_size = pipe_size; - usbhsh_ureq_list_init(hpriv); usbhsh_port_stat_init(hpriv); /* init all device */ @@ -1334,8 +1273,6 @@ int usbhs_mod_host_remove(struct usbhs_priv *priv) struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - usbhsh_ureq_list_quit(hpriv); - usb_put_hcd(hcd); return 0; From ab14230854aba9d0c99b3cd0e4bb1ef430973d84 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:48:00 -0700 Subject: [PATCH 18/50] usb: gadget: renesas_usbhs: check device0 status when alloc device0 was treated without checking in usbhsh_device_alloc(). but "udev->usbv" and "dev_set_drvdata()" will be overwritten if device0 was multi-allocated. This patch fixes this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3f1eaf15e0ba..e6fd044adfa3 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -153,6 +153,7 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev) #define usbhsh_udev_to_usbv(h) ((h)->usbv) +#define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h) #define usbhsh_pipe_info(p) ((p)->mod_private) @@ -231,27 +232,34 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, int i; /* - * device 0 + * find device */ if (0 == usb_pipedevice(urb->pipe)) { + /* + * device0 is special case + */ udev = usbhsh_device0(hpriv); - goto usbhsh_device_find; + if (usbhsh_udev_is_used(udev)) + udev = NULL; + } else { + struct usbhsh_device *pos; + + /* + * find unused device + */ + usbhsh_for_each_udev(pos, hpriv, i) { + if (usbhsh_udev_is_used(pos)) + continue; + udev = pos; + break; + } } - /* - * find unused device - */ - usbhsh_for_each_udev(udev, hpriv, i) { - if (usbhsh_udev_to_usbv(udev)) - continue; - goto usbhsh_device_find; + if (!udev) { + dev_err(dev, "no free usbhsh_device\n"); + return NULL; } - dev_err(dev, "no free usbhsh_device\n"); - - return NULL; - -usbhsh_device_find: if (usbhsh_device_has_endpoint(udev)) dev_warn(dev, "udev have old endpoint\n"); From d399f90d192f4cbda2527d42d054d090e327a9a0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:48:35 -0700 Subject: [PATCH 19/50] usb: gadget: renesas_usbhs: adds spin lock area on mod_host spin lock was needed in mod_host. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 67 ++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index e6fd044adfa3..1816a3e11b78 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -228,9 +228,13 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + unsigned long flags; u16 upphub, hubport; int i; + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + /* * find device */ @@ -255,6 +259,19 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, } } + if (udev) { + /* + * usbhsh_usbv_to_udev() + * usbhsh_udev_to_usbv() + * will be enable + */ + dev_set_drvdata(&usbv->dev, udev); + udev->usbv = usbv; + } + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + if (!udev) { dev_err(dev, "no free usbhsh_device\n"); return NULL; @@ -266,14 +283,6 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, /* uep will be attached */ INIT_LIST_HEAD(&udev->ep_list_head); - /* - * usbhsh_usbv_to_udev() - * usbhsh_udev_to_usbv() - * will be enable - */ - dev_set_drvdata(&usbv->dev, udev); - udev->usbv = usbv; - upphub = 0; hubport = 0; if (!usbhsh_connected_to_rhdev(hcd, udev)) { @@ -302,8 +311,10 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, struct usbhsh_device *udev) { struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_udev_to_usbv(udev); + unsigned long flags; dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); @@ -311,6 +322,9 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, if (usbhsh_device_has_endpoint(udev)) dev_warn(dev, "udev still have endpoint\n"); + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + /* * usbhsh_usbv_to_udev() * usbhsh_udev_to_usbv() @@ -318,6 +332,9 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, */ dev_set_drvdata(&usbv->dev, NULL); udev->usbv = NULL; + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ } /* @@ -338,6 +355,7 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, struct usb_endpoint_descriptor *desc = &ep->desc; int type, i, dir_in; unsigned int min_usr; + unsigned long flags; dir_in_req = !!dir_in_req; @@ -352,6 +370,9 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, goto usbhsh_endpoint_alloc_find_pipe; } + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + /* * find best pipe for endpoint * see @@ -376,6 +397,19 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, } } + if (best_pipe) { + /* update pipe user count */ + info = usbhsh_pipe_info(best_pipe); + info->usr_cnt++; + + /* init this endpoint, and attach it to udev */ + INIT_LIST_HEAD(&uep->ep_list); + list_add_tail(&uep->ep_list, &udev->ep_list_head); + } + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + if (unlikely(!best_pipe)) { dev_err(dev, "couldn't find best pipe\n"); kfree(uep); @@ -390,16 +424,6 @@ usbhsh_endpoint_alloc_find_pipe: usbhsh_uep_to_udev(uep) = udev; usbhsh_ep_to_uep(ep) = uep; - /* - * update pipe user count - */ - info = usbhsh_pipe_info(best_pipe); - info->usr_cnt++; - - /* init this endpoint, and attach it to udev */ - INIT_LIST_HEAD(&uep->ep_list); - list_add_tail(&uep->ep_list, &udev->ep_list_head); - /* * usbhs_pipe_config_update() should be called after * usbhs_set_device_config() @@ -426,6 +450,7 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, struct device *dev = usbhs_priv_to_dev(priv); struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); struct usbhsh_pipe_info *info; + unsigned long flags; if (!uep) return; @@ -434,6 +459,9 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), usbhs_pipe_name(uep->pipe), uep); + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + info = usbhsh_pipe_info(uep->pipe); info->usr_cnt--; @@ -443,6 +471,9 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, usbhsh_uep_to_udev(uep) = NULL; usbhsh_ep_to_uep(ep) = NULL; + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + kfree(uep); } From f352741d2704a480a927160be8c910570bf51238 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:48:22 -0700 Subject: [PATCH 20/50] usb: gadget: renesas_usbhs: cleanup usbhsh_endpoint_xxx() this patch cleanup - make sure static function - remove unneeded label - useless local variable were removed Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 53 +++++++++++++--------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 1816a3e11b78..e09b64a92a4e 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -340,36 +340,26 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, /* * end-point control */ -struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, +static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, struct usbhsh_device *udev, struct usb_host_endpoint *ep, int dir_in_req, gfp_t mem_flags) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct usbhsh_ep *uep; struct usbhsh_pipe_info *info; - struct usbhs_pipe *pipe, *best_pipe; - struct device *dev = usbhsh_hcd_to_dev(hcd); + struct usbhs_pipe *best_pipe = NULL; + struct device *dev = usbhs_priv_to_dev(priv); struct usb_endpoint_descriptor *desc = &ep->desc; - int type, i, dir_in; - unsigned int min_usr; unsigned long flags; - dir_in_req = !!dir_in_req; - uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); if (!uep) { dev_err(dev, "usbhsh_ep alloc fail\n"); return NULL; } - if (usb_endpoint_xfer_control(desc)) { - best_pipe = usbhsh_hpriv_to_dcp(hpriv); - goto usbhsh_endpoint_alloc_find_pipe; - } - /******************** spin lock ********************/ usbhs_lock(priv, flags); @@ -378,22 +368,29 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, * see * HARDWARE LIMITATION */ - type = usb_endpoint_type(desc); - min_usr = ~0; - best_pipe = NULL; - usbhs_for_each_pipe(pipe, priv, i) { - if (!usbhs_pipe_type_is(pipe, type)) - continue; + if (usb_endpoint_xfer_control(desc)) { + /* best pipe is DCP */ + best_pipe = usbhsh_hpriv_to_dcp(hpriv); + } else { + struct usbhs_pipe *pipe; + unsigned int min_usr = ~0; + int i, dir_in; - dir_in = !!usbhs_pipe_is_dir_in(pipe); - if (0 != (dir_in - dir_in_req)) - continue; + dir_in_req = !!dir_in_req; - info = usbhsh_pipe_info(pipe); + usbhs_for_each_pipe(pipe, priv, i) { + if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) + continue; - if (min_usr > info->usr_cnt) { - min_usr = info->usr_cnt; - best_pipe = pipe; + dir_in = !!usbhs_pipe_is_dir_in(pipe); + if (0 != (dir_in - dir_in_req)) + continue; + + info = usbhsh_pipe_info(pipe); + if (min_usr > info->usr_cnt) { + min_usr = info->usr_cnt; + best_pipe = pipe; + } } } @@ -415,7 +412,7 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, kfree(uep); return NULL; } -usbhsh_endpoint_alloc_find_pipe: + /* * init uep */ @@ -443,7 +440,7 @@ usbhsh_endpoint_alloc_find_pipe: return uep; } -void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, +static void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, struct usb_host_endpoint *ep) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); From 3eddc9e4c828dbbeabb5924266bfded42a1ac042 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:48:46 -0700 Subject: [PATCH 21/50] usb: gadget: renesas_usbhs: parameter cleanup for usbhsh_xx_queue_push() This patch remove unneeded parameter from usbhsh_xx_queue_push() Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index e09b64a92a4e..887cf686bca9 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -500,11 +500,12 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) } static int usbhsh_queue_push(struct usb_hcd *hcd, - struct usbhs_pipe *pipe, struct urb *urb, gfp_t mem_flags) { struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); + struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); + struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); struct device *dev = usbhsh_hcd_to_dev(hcd); struct usbhsh_request *ureq; void *buf; @@ -666,11 +667,12 @@ static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, } static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, - struct usbhs_pipe *pipe, struct urb *urb, gfp_t mflags) { struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); + struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); + struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); struct device *dev = usbhsh_hcd_to_dev(hcd); int ret; @@ -743,7 +745,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usb_host_endpoint *ep = urb->ep; struct usbhsh_device *udev, *new_udev = NULL; - struct usbhs_pipe *pipe; struct usbhsh_ep *uep; int is_dir_in = usb_pipein(urb->pipe); @@ -777,15 +778,14 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, if (!uep) goto usbhsh_urb_enqueue_error_free_device; } - pipe = usbhsh_uep_to_pipe(uep); /* * push packet */ if (usb_pipecontrol(urb->pipe)) - ret = usbhsh_dcp_queue_push(hcd, pipe, urb, mem_flags); + ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags); else - ret = usbhsh_queue_push(hcd, pipe, urb, mem_flags); + ret = usbhsh_queue_push(hcd, urb, mem_flags); return ret; From 4825093e9d0692a2a1f1615ab69246ac07b17f2f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:48:59 -0700 Subject: [PATCH 22/50] usb: gadget: renesas_usbhs: parameter cleanup for usbhsh_endpoint_xx() current mod_host used usbhs_endpoint_alloc/free(), but allocated variable was attached to each xx->hcpriv. The intuitively clear name was not xxx_alloc/free() but xxx_attach/detach(). Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 37 +++++++++++++--------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 887cf686bca9..11c615d8d0d2 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -340,13 +340,14 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, /* * end-point control */ -static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, - struct usbhsh_device *udev, - struct usb_host_endpoint *ep, - int dir_in_req, - gfp_t mem_flags) +static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, + struct urb *urb, + gfp_t mem_flags) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usb_device *usbv = usbhsh_urb_to_usbv(urb); + struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + struct usb_host_endpoint *ep = urb->ep; struct usbhsh_ep *uep; struct usbhsh_pipe_info *info; struct usbhs_pipe *best_pipe = NULL; @@ -357,7 +358,7 @@ static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); if (!uep) { dev_err(dev, "usbhsh_ep alloc fail\n"); - return NULL; + return -ENOMEM; } /******************** spin lock ********************/ @@ -374,10 +375,9 @@ static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, } else { struct usbhs_pipe *pipe; unsigned int min_usr = ~0; + int dir_in_req = !!usb_pipein(urb->pipe); int i, dir_in; - dir_in_req = !!dir_in_req; - usbhs_for_each_pipe(pipe, priv, i) { if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) continue; @@ -410,7 +410,7 @@ static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, if (unlikely(!best_pipe)) { dev_err(dev, "couldn't find best pipe\n"); kfree(uep); - return NULL; + return -EIO; } /* @@ -437,11 +437,11 @@ static struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, usbhsh_device_number(hpriv, udev), usbhs_pipe_name(uep->pipe), uep); - return uep; + return 0; } -static void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, - struct usb_host_endpoint *ep) +static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, + struct usb_host_endpoint *ep) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); struct device *dev = usbhs_priv_to_dev(priv); @@ -745,7 +745,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usb_host_endpoint *ep = urb->ep; struct usbhsh_device *udev, *new_udev = NULL; - struct usbhsh_ep *uep; int is_dir_in = usb_pipein(urb->pipe); int ret; @@ -769,13 +768,11 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, } /* - * get uep + * attach endpoint if needed */ - uep = usbhsh_ep_to_uep(ep); - if (!uep) { - uep = usbhsh_endpoint_alloc(hpriv, udev, ep, - is_dir_in, mem_flags); - if (!uep) + if (!usbhsh_ep_to_uep(ep)) { + ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); + if (ret < 0) goto usbhsh_urb_enqueue_error_free_device; } @@ -827,7 +824,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, udev = usbhsh_uep_to_udev(uep); hpriv = usbhsh_hcd_to_hpriv(hcd); - usbhsh_endpoint_free(hpriv, ep); + usbhsh_endpoint_detach(hpriv, ep); /* * if there is no endpoint, From 7aac8d1537b1fd1a9e39bd16edcd6728c19f8dd5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 31 Oct 2011 00:49:09 -0700 Subject: [PATCH 23/50] usb: gadget: renesas_usbhs: parameter cleanup for usbhsh_device_xx() current mod_host used usbhs_device_alloc/free(), but allocated variable was attached to each xx->hcpriv. The intuitively clear name was not xxx_alloc/free() but xxx_attach/detach(). Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 11c615d8d0d2..182bdb8e45ec 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -220,7 +220,7 @@ static int usbhsh_device_has_endpoint(struct usbhsh_device *udev) return !list_empty(&udev->ep_list_head); } -static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, +static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, struct urb *urb) { struct usbhsh_device *udev = NULL; @@ -307,7 +307,7 @@ static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, return udev; } -static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, +static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, struct usbhsh_device *udev) { struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); @@ -744,7 +744,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct device *dev = usbhs_priv_to_dev(priv); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_device *udev, *new_udev = NULL; + struct usbhsh_device *new_udev = NULL; int is_dir_in = usb_pipein(urb->pipe); int ret; @@ -756,15 +756,12 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, goto usbhsh_urb_enqueue_error_not_linked; /* - * get udev + * attach udev if needed */ - udev = usbhsh_usbv_to_udev(usbv); - if (!udev) { - new_udev = usbhsh_device_alloc(hpriv, urb); + if (!usbhsh_usbv_to_udev(usbv)) { + new_udev = usbhsh_device_attach(hpriv, urb); if (!new_udev) goto usbhsh_urb_enqueue_error_not_linked; - - udev = new_udev; } /* @@ -788,7 +785,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, usbhsh_urb_enqueue_error_free_device: if (new_udev) - usbhsh_device_free(hpriv, new_udev); + usbhsh_device_detach(hpriv, new_udev); usbhsh_urb_enqueue_error_not_linked: dev_dbg(dev, "%s error\n", __func__); @@ -831,7 +828,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, * free device */ if (!usbhsh_device_has_endpoint(udev)) - usbhsh_device_free(hpriv, udev); + usbhsh_device_detach(hpriv, udev); } static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) From d327ab5b6d660d6fe22b073b743fde1668e593bb Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 19 Nov 2011 18:27:37 +0100 Subject: [PATCH 24/50] usb: gadget: replace usb_gadget::is_dualspeed with max_speed This commit replaces usb_gadget's is_dualspeed field with a max_speed field. [ balbi@ti.com : Fixed DWC3 driver ] Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- Documentation/feature-removal-schedule.txt | 14 ++++++++++++ drivers/usb/dwc3/gadget.c | 2 +- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 2 +- drivers/usb/gadget/ci13xxx_udc.c | 7 ++++-- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 6 ++--- drivers/usb/gadget/fsl_udc_core.c | 2 +- drivers/usb/gadget/fusb300_udc.c | 2 +- drivers/usb/gadget/goku_udc.c | 1 + drivers/usb/gadget/langwell_udc.c | 2 +- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/mv_udc_core.c | 2 +- drivers/usb/gadget/net2272.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 1 + drivers/usb/gadget/pch_udc.c | 2 +- drivers/usb/gadget/printer.c | 4 ++-- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 2 +- drivers/usb/gadget/udc-core.c | 26 +++++++++++++++++----- drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- include/linux/usb/gadget.h | 10 ++++----- 25 files changed, 68 insertions(+), 35 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3d849122b5b1..a7e4ac1202d6 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -535,6 +535,20 @@ Why: In 3.0, we can now autodetect internal 3G device and already have information log when acer-wmi initial. Who: Lee, Chun-Yi +--------------------------- + +What: /sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and + is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file. +When: 3.8 +Why: The is_dualspeed file is superseded by maximum_speed in the same + directory and is_dualspeed line in device file is superseded by + max_speed line in the same file. + + The maximum_speed/max_speed specifies maximum speed supported by UDC. + To check if dualspeeed is supported, check if the value is >= 3. + Various possible speeds are defined in . +Who: Michal Nazarewicz + ---------------------------- What: The XFS nodelaylog mount option diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25dbd8614e72..580272042a33 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1986,7 +1986,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) dev_set_name(&dwc->gadget.dev, "gadget"); dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.is_dualspeed = true; + dwc->gadget.max_speed = USB_SPEED_SUPER; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.dev.parent = dwc->dev; diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 45f422ac103f..e69cdbca8017 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3349,7 +3349,7 @@ static int udc_probe(struct udc *dev) dev_set_name(&dev->gadget.dev, "gadget"); dev->gadget.dev.release = gadget_release; dev->gadget.name = name; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* init registers, interrupts, ... */ startup_registers(dev); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 271a9d873608..e2fb6d583bd9 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1038,7 +1038,7 @@ static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), - .is_dualspeed = 1, + .max_speed = USB_SPEED_HIGH, .name = "atmel_usba_udc", .dev = { .init_name = "gadget", diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 8956a2448b33..9767d9170fbd 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -766,8 +766,11 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", gadget->speed); + n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", + gadget->max_speed); + /* TODO: Scheduled for removal in 3.8. */ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget->is_dualspeed); + gadget_is_dualspeed(gadget)); n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", gadget->is_otg); n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", @@ -2880,7 +2883,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, udc->gadget.ops = &usb_gadget_ops; udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.is_dualspeed = 1; + udc->gadget.max_speed = USB_SPEED_HIGH; udc->gadget.is_otg = 0; udc->gadget.name = driver->name; diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index ab8f1b488d54..cf235d84d8b7 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -977,7 +977,7 @@ static int dummy_udc_probe (struct platform_device *pdev) dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; - dum->gadget.is_dualspeed = 1; + dum->gadget.max_speed = USB_SPEED_SUPER; dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 596a0b464e61..38bcbfb91f62 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -152,7 +152,7 @@ ep_matches ( switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget->is_dualspeed && max > 64) + if (!gadget_is_dualspeed(gadget) && max > 64) return 0; /* FALLTHROUGH */ @@ -160,12 +160,12 @@ ep_matches ( /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ if (ep->maxpacket < max) return 0; - if (!gadget->is_dualspeed && max > 1023) + if (!gadget_is_dualspeed(gadget) && max > 1023) return 0; /* BOTH: "high bandwidth" works only at high speed */ if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) return 0; /* configure your hardware with enough buffering!! */ } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index dd28ef3def71..6de8ec753818 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2525,7 +2525,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) /* Setup gadget structure */ udc_controller->gadget.ops = &fsl_gadget_ops; - udc_controller->gadget.is_dualspeed = 1; + udc_controller->gadget.max_speed = USB_SPEED_HIGH; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 74da206c8406..6e32a60ab3b7 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1463,7 +1463,7 @@ static int __init fusb300_probe(struct platform_device *pdev) dev_set_name(&fusb300->gadget.dev, "gadget"); - fusb300->gadget.is_dualspeed = 1; + fusb300->gadget.max_speed = USB_SPEED_HIGH; fusb300->gadget.dev.parent = &pdev->dev; fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; fusb300->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 7f87805cddc4..ab9c924eee76 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1796,6 +1796,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&dev->lock); dev->pdev = pdev; dev->gadget.ops = &goku_ops; + dev->gadget.max_speed = USB_SPEED_FULL; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index c9fa3bf5b377..fa0fcc11263f 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -3267,7 +3267,7 @@ static int langwell_udc_probe(struct pci_dev *pdev, dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.is_dualspeed = 1; /* support dual speed */ + dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ #ifdef OTG_TRANSCEIVER dev->gadget.is_otg = 1; /* support otg mode */ #endif diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 9aa1cbbee45b..a7692c208ea7 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1653,7 +1653,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->gadget.ops = &m66592_gadget_ops; device_initialize(&m66592->gadget.dev); dev_set_name(&m66592->gadget.dev, "gadget"); - m66592->gadget.is_dualspeed = 1; + m66592->gadget.max_speed = USB_SPEED_HIGH; m66592->gadget.dev.parent = &pdev->dev; m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; m66592->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 892412103dd8..9376a7483c9b 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2312,7 +2312,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - udc->gadget.is_dualspeed = 1; /* support dual speed */ + udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&udc->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index d1b76368472f..d5050f4e8449 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -2235,7 +2235,7 @@ net2272_probe_init(struct device *dev, unsigned int irq) ret->irq = irq; ret->dev = dev; ret->gadget.ops = &net2272_ops; - ret->gadget.is_dualspeed = 1; + ret->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&ret->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index da2b9d0be3ca..9ee36fd5adae 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2698,7 +2698,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 788989a10223..ed01a0f5f119 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2676,6 +2676,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->iso); udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_FULL; udc->gadget.name = driver_name; device_initialize(&udc->gadget.dev); diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 5048a0c07640..7f97b4adba3e 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2941,7 +2941,7 @@ static int pch_udc_probe(struct pci_dev *pdev, dev->gadget.dev.dma_mask = pdev->dev.dma_mask; dev->gadget.dev.release = gadget_release; dev->gadget.name = KBUILD_MODNAME; - dev->gadget.is_dualspeed = 1; + dev->gadget.max_speed = USB_SPEED_HIGH; retval = device_register(&dev->gadget.dev); if (retval) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 65a8834f274b..b74f49ac95e5 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1141,7 +1141,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* * assumes ep0 uses the same value for both @@ -1155,7 +1155,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) break; case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget->is_dualspeed) + if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ #endif /* CONFIG_USB_GADGET_DUALSPEED */ diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index fc719a3f8557..3666d7c54e24 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1911,7 +1911,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->gadget.ops = &r8a66597_gadget_ops; dev_set_name(&r8a66597->gadget.dev, "gadget"); - r8a66597->gadget.is_dualspeed = 1; + r8a66597->gadget.max_speed = USB_SPEED_HIGH; r8a66597->gadget.dev.parent = &pdev->dev; r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; r8a66597->gadget.dev.release = pdev->dev.release; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index b31448229f0b..6bc7ad87c306 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3362,7 +3362,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) dev_set_name(&hsotg->gadget.dev, "gadget"); - hsotg->gadget.is_dualspeed = 1; + hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 20a553b46aed..09ea96558b91 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1310,7 +1310,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) device_initialize(&hsudc->gadget.dev); dev_set_name(&hsudc->gadget.dev, "gadget"); - hsudc->gadget.is_dualspeed = 1; + hsudc->gadget.max_speed = USB_SPEED_HIGH; hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.name = dev_name(dev); hsudc->gadget.dev.parent = dev; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 6939e17f4580..0b0d12ccc487 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -371,14 +371,28 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); -static ssize_t usb_udc_speed_show(struct device *dev, +#define USB_UDC_SPEED_ATTR(name, param) \ +ssize_t usb_udc_##param##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + return snprintf(buf, PAGE_SIZE, "%s\n", \ + usb_speed_string(udc->gadget->param)); \ +} \ +static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) + +static USB_UDC_SPEED_ATTR(current_speed, speed); +static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); + +/* TODO: Scheduled for removal in 3.8. */ +static ssize_t usb_udc_is_dualspeed_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - usb_speed_string(udc->gadget->speed)); + return snprintf(buf, PAGE_SIZE, "%d\n", + gadget_is_dualspeed(udc->gadget)); } -static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL); +static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ @@ -391,7 +405,6 @@ ssize_t usb_udc_##name##_show(struct device *dev, \ } \ static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL) -static USB_UDC_ATTR(is_dualspeed); static USB_UDC_ATTR(is_otg); static USB_UDC_ATTR(is_a_peripheral); static USB_UDC_ATTR(b_hnp_enable); @@ -401,7 +414,8 @@ static USB_UDC_ATTR(a_alt_hnp_support); static struct attribute *usb_udc_attrs[] = { &dev_attr_srp.attr, &dev_attr_soft_connect.attr, - &dev_attr_speed.attr, + &dev_attr_current_speed.attr, + &dev_attr_maximum_speed.attr, &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 922148ff8d29..47a3d1e5b28b 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1844,7 +1844,7 @@ int __init musb_gadget_setup(struct musb *musb) */ musb->g.ops = &musb_gadget_operations; - musb->g.is_dualspeed = 1; + musb->g.max_speed = USB_SPEED_HIGH; musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 8fb9056ff48d..43c67e5cde26 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -862,7 +862,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) gpriv->gadget.dev.parent = dev; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; - gpriv->gadget.is_dualspeed = 1; + gpriv->gadget.max_speed = USB_SPEED_HIGH; ret = device_register(&gpriv->gadget.dev); if (ret < 0) goto err_add_udc; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 1d3a67523ffc..98dc306898b5 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -477,8 +477,8 @@ struct usb_gadget_ops { * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. - * @is_dualspeed: True if the controller supports both high and full speed - * operation. If it does, the gadget driver must also support both. + * @max_speed: Maximal speed the UDC can handle. UDC must support this + * and all slower speeds. * @is_otg: True if the USB device port uses a Mini-AB jack, so that the * gadget driver must provide a USB OTG descriptor. * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable @@ -518,7 +518,7 @@ struct usb_gadget { struct usb_ep *ep0; struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; - unsigned is_dualspeed:1; + enum usb_device_speed max_speed; unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; @@ -549,7 +549,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) static inline int gadget_is_dualspeed(struct usb_gadget *g) { #ifdef CONFIG_USB_GADGET_DUALSPEED - /* runtime test would check "g->is_dualspeed" ... that might be + /* runtime test would check "g->max_speed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; @@ -567,7 +567,7 @@ static inline int gadget_is_superspeed(struct usb_gadget *g) { #ifdef CONFIG_USB_GADGET_SUPERSPEED /* - * runtime test would check "g->is_superspeed" ... that might be + * runtime test would check "g->max_speed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; From 7177aed44f515d949f587170e0e177ce17e74793 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 19 Nov 2011 18:27:38 +0100 Subject: [PATCH 25/50] usb: gadget: rename usb_gadget_driver::speed to max_speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit renames the “speed” field of the usb_gadget_driver structure to “max_speed”. This is so that to make it more apparent that the field represents the maximum speed gadget driver can support. This also make the field look more like fields with the same name in usb_gadget and usb_composite_driver structures. All of those represent the *maximal* speed given entity supports. After this commit, there are the following fields in various structures: * usb_gadget::speed - the current connection speed, * usb_gadget::max_speed - maximal speed UDC supports, * usb_gadget_driver::max_speed - maximal speed gadget driver supports, and * usb_composite_driver::max_speed - maximal speed composite gadget supports. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/amd5536udc.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/ci13xxx_udc.c | 2 +- drivers/usb/gadget/composite.c | 8 ++++---- drivers/usb/gadget/dbgp.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 13 ++++++------- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/fsl_qe_udc.c | 4 ++-- drivers/usb/gadget/fsl_udc_core.c | 2 +- drivers/usb/gadget/fusb300_udc.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/imx_udc.c | 2 +- drivers/usb/gadget/inode.c | 6 +++--- drivers/usb/gadget/m66592-udc.c | 2 +- drivers/usb/gadget/net2272.c | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pch_udc.c | 2 +- drivers/usb/gadget/printer.c | 2 +- drivers/usb/gadget/pxa25x_udc.c | 2 +- drivers/usb/gadget/pxa27x_udc.c | 2 +- drivers/usb/gadget/r8a66597-udc.c | 2 +- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 4 ++-- drivers/usb/musb/musb_gadget.c | 2 +- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- include/linux/usb/gadget.h | 4 ++-- 28 files changed, 41 insertions(+), 42 deletions(-) diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e69cdbca8017..e9a2c5c44454 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, u32 tmp; if (!driver || !bind || !driver->setup - || driver->speed < USB_SPEED_HIGH) + || driver->max_speed < USB_SPEED_HIGH) return -EINVAL; if (!dev) return -ENODEV; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 8efe0fa9228d..ac41f71bf9ca 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver, unsigned long flags; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) { DBG("bad parameter.\n"); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 9767d9170fbd..27e313718422 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -813,7 +813,7 @@ static ssize_t show_driver(struct device *dev, struct device_attribute *attr, n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", (driver->function ? driver->function : "")); n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->speed); + driver->max_speed); return n; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f71b0787983f..a95de6a4a134 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { #ifdef CONFIG_USB_GADGET_SUPERSPEED - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, #else - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #endif .unbind = composite_unbind, @@ -1584,8 +1584,8 @@ int usb_composite_probe(struct usb_composite_driver *driver, driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; - composite_driver.speed = min((u8)composite_driver.speed, - (u8)driver->max_speed); + composite_driver.max_speed = + min_t(u8, composite_driver.max_speed, driver->max_speed); composite = driver; composite_gadget_bind = bind; diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c index 6256420089f3..19d7bb0df75a 100644 --- a/drivers/usb/gadget/dbgp.c +++ b/drivers/usb/gadget/dbgp.c @@ -404,7 +404,7 @@ fail: static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index cf235d84d8b7..db815c2da7ed 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -823,19 +823,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) if (value && dum->driver) { if (mod_data.is_super_speed) - dum->gadget.speed = dum->driver->speed; + dum->gadget.speed = dum->driver->max_speed; else if (mod_data.is_high_speed) dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, - dum->driver->speed); + dum->driver->max_speed); else dum->gadget.speed = USB_SPEED_FULL; dummy_udc_udpate_ep0(dum); - if (dum->gadget.speed < dum->driver->speed) + if (dum->gadget.speed < dum->driver->max_speed) dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - (dum->driver->speed == USB_SPEED_SUPER ? - "SuperSpeed" : "HighSpeed")); + " if you connect it to a %s port...\n", + usb_speed_string(dum->driver->max_speed)); } dum_hcd = gadget_to_dummy_hcd(_gadget); @@ -898,7 +897,7 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->speed == USB_SPEED_UNKNOWN) + if (driver->max_speed == USB_SPEED_UNKNOWN) return -EINVAL; /* diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index e8ff2f1c06cc..e0f30fc70e45 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3604,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { - .speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index e00cf92409ce..b7a1efef938d 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->speed < USB_SPEED_FULL + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -2350,7 +2350,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); + udc_controller->gadget.speed = driver->max_speed; spin_unlock_irqrestore(&udc_controller->lock, flags); retval = bind(&udc_controller->gadget); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 6de8ec753818..d7ea6c076ce9 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->speed < USB_SPEED_FULL + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 6e32a60ab3b7..5831cb4a0b35 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ab9c924eee76..5af70fcce139 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 2d978c0e7ced..8d1c75abd73d 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 6ccae2707e59..93612519b53a 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) static struct usb_gadget_driver gadgetfs_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, #else - .speed = USB_SPEED_FULL, + .max_speed = USB_SPEED_FULL, #endif .function = (char *) driver_desc, .unbind = gadgetfs_unbind, @@ -1792,7 +1792,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget) } static struct usb_gadget_driver probe_driver = { - .speed = USB_SPEED_HIGH, + .max_speed = USB_SPEED_HIGH, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index a7692c208ea7..3608b3bd5732 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index d5050f4e8449..4c81d540bc26 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget, unsigned i; if (!driver || !driver->unbind || !driver->setup || - driver->speed != USB_SPEED_HIGH) + driver->max_speed != USB_SPEED_HIGH) return -EINVAL; dev = container_of(_gadget, struct net2272, gadget); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 9ee36fd5adae..cf1f36454d08 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver || driver->speed < USB_SPEED_HIGH + if (!driver || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index ed01a0f5f119..7db5bbe6251b 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2110,7 +2110,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver, return -ENODEV; if (!driver // FIXME if otg, check: driver->is_otg - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 7f97b4adba3e..dd2313cce1d3 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2693,7 +2693,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver, struct pch_udc_dev *dev = pch_udc; int retval; - if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind || + if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind || !driver->setup || !driver->unbind || !driver->disconnect) { dev_err(&dev->pdev->dev, "%s: invalid driver parameter\n", __func__); diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index b74f49ac95e5..d83134b0f78a 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1535,7 +1535,7 @@ fail: /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver printer_driver = { - .speed = DEVSPEED, + .max_speed = DEVSPEED, .function = (char *) driver_desc, .unbind = printer_unbind, diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index c090a7e3ecf8..dd470635f4f7 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 18b6b091f2a6..f4c44eb806c3 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1807,7 +1807,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver, struct pxa_udc *udc = the_controller; int retval; - if (!driver || driver->speed < USB_SPEED_FULL || !bind + if (!driver || driver->max_speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!udc) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 3666d7c54e24..f5b8d215e1d5 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget, struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); if (!driver - || driver->speed < USB_SPEED_HIGH + || driver->max_speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; if (!r8a66597) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6bc7ad87c306..d098c36cb587 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return -EINVAL; } - if (driver->speed < USB_SPEED_FULL) + if (driver->max_speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); if (!bind || !driver->setup) { diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 09ea96558b91..f398b8590f9c 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1142,7 +1142,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, int ret; if (!driver - || driver->speed < USB_SPEED_FULL + || driver->max_speed < USB_SPEED_FULL || !bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index b8643771fa80..4d860e9460a4 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, if (udc->driver) return -EBUSY; - if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { + if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->speed); + bind, driver->setup, driver->max_speed); return -EINVAL; } #if defined(MODULE) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 47a3d1e5b28b..3148461287b1 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1903,7 +1903,7 @@ static int musb_gadget_start(struct usb_gadget *g, unsigned long flags; int retval = -EINVAL; - if (driver->speed < USB_SPEED_HIGH) + if (driver->max_speed < USB_SPEED_HIGH) goto err0; pm_runtime_get_sync(musb->controller); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 43c67e5cde26..c307c8f5bd3a 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -751,7 +751,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, if (!driver || !driver->setup || - driver->speed < USB_SPEED_FULL) + driver->max_speed < USB_SPEED_FULL) return -EINVAL; /* first hook up the driver ... */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 98dc306898b5..317d8925387c 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -760,7 +760,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) /** * struct usb_gadget_driver - driver for usb 'slave' devices * @function: String describing the gadget's function - * @speed: Highest speed the driver handles. + * @max_speed: Highest speed the driver handles. * @setup: Invoked for ep0 control requests that aren't handled by * the hardware level driver. Most calls must be handled by * the gadget driver, including descriptor and configuration @@ -824,7 +824,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) */ struct usb_gadget_driver { char *function; - enum usb_device_speed speed; + enum usb_device_speed max_speed; void (*unbind)(struct usb_gadget *); int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); From 4b815932013c9f94f852df9d136dcd5c0008afe2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:27:19 -0800 Subject: [PATCH 26/50] usb: renesas_usbhs: remove superfluous usbhs_lock from recip handler recip handler will call various functions which are holding usbhs_lock. This patch removes superfluous usbhs_lock from recip handler to escape double lock. [ balbi@ti.com : brushed up commit log a bit ] Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index c307c8f5bd3a..9a9e36378e87 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -327,15 +327,8 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv, } if (func) { - unsigned long flags; - dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); ret = func(priv, uep, ctrl); - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ } usbhsg_recip_run_handle_end: From 9cf1b06e906d8590fc027264af30b37754bd8226 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:27:32 -0800 Subject: [PATCH 27/50] usb: renesas_usbhs: add usbhs_pipe_is_stall() This is preparation for chapter 9 test Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/pipe.c | 7 +++++++ drivers/usb/renesas_usbhs/pipe.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c74389ce2177..c36ad4c3a259 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -257,6 +257,13 @@ void usbhs_pipe_stall(struct usbhs_pipe *pipe) } } +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) +{ + u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; + + return (int)(pid == PID_STALL10 || pid == PID_STALL11); +} + /* * pipe setup */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 6334fc644cc0..fa18b7dc2b2a 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -87,6 +87,7 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe); +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, u16 epnum, u16 maxp); From ced6e09e6ec4f52c9bd76d6b8debd67517fdcc1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:27:50 -0800 Subject: [PATCH 28/50] usb: renesas_usbhs: add basic USB_REQ_SET_FEATURE support This patch adds basic set-feature support for chapter 9 test. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 9a9e36378e87..3130089eacff 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -281,6 +281,29 @@ struct usbhsg_recip_handle req_clear_feature = { .endpoint = usbhsg_recip_handler_std_clear_endpoint, }; +/* + * USB_TYPE_STANDARD / set feature functions + */ +static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + + usbhs_pipe_stall(pipe); + + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + + return 0; +} + +struct usbhsg_recip_handle req_set_feature = { + .name = "set feature", + .device = usbhsg_recip_handler_std_control_done, + .interface = usbhsg_recip_handler_std_control_done, + .endpoint = usbhsg_recip_handler_std_set_endpoint, +}; + /* * USB_TYPE handler */ @@ -405,6 +428,9 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, case USB_REQ_CLEAR_FEATURE: recip_handler = &req_clear_feature; break; + case USB_REQ_SET_FEATURE: + recip_handler = &req_set_feature; + break; } } From 17f7f76940214af91bfefcf9a2ca156701d905e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:28:04 -0800 Subject: [PATCH 29/50] usb: renesas_usbhs: add basic USB_REQ_GET_STATUS support This patch adds basic get-status support for chapter 9 test. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 101 +++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 3130089eacff..812960ba95e1 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -304,6 +304,104 @@ struct usbhsg_recip_handle req_set_feature = { .endpoint = usbhsg_recip_handler_std_set_endpoint, }; +/* + * USB_TYPE_STANDARD / get status functions + */ +static void __usbhsg_recip_send_complete(struct usb_ep *ep, + struct usb_request *req) +{ + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + + /* free allocated recip-buffer/usb_request */ + kfree(ureq->pkt.buf); + usb_ep_free_request(ep, req); +} + +static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, + unsigned short status) +{ + struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usb_request *req; + unsigned short *buf; + + /* alloc new usb_request for recip */ + req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); + if (!req) { + dev_err(dev, "recip request allocation fail\n"); + return; + } + + /* alloc recip data buffer */ + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) { + usb_ep_free_request(&dcp->ep, req); + dev_err(dev, "recip data allocation fail\n"); + return; + } + + /* recip data is status */ + *buf = cpu_to_le16(status); + + /* allocated usb_request/buffer will be freed */ + req->complete = __usbhsg_recip_send_complete; + req->buf = buf; + req->length = sizeof(*buf); + req->zero = 0; + + /* push packet */ + pipe->handler = &usbhs_fifo_pio_push_handler; + usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req)); +} + +static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + unsigned short status = 1 << USB_DEVICE_SELF_POWERED; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + unsigned short status = 0; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + unsigned short status = 0; + + if (usbhs_pipe_is_stall(pipe)) + status = 1 << USB_ENDPOINT_HALT; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +struct usbhsg_recip_handle req_get_status = { + .name = "get status", + .device = usbhsg_recip_handler_std_get_device, + .interface = usbhsg_recip_handler_std_get_interface, + .endpoint = usbhsg_recip_handler_std_get_endpoint, +}; + /* * USB_TYPE handler */ @@ -431,6 +529,9 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, case USB_REQ_SET_FEATURE: recip_handler = &req_set_feature; break; + case USB_REQ_GET_STATUS: + recip_handler = &req_get_status; + break; } } From 25fa70795bf11ef6f5b147f0b231a43880ba96ca Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:28:17 -0800 Subject: [PATCH 30/50] usb: renesas_usbhs: send packet in necessary timing. Current renesas_usbhs driver always tries to send packet in end of recip handler. But it breaks chapter 9 EndpointHalt test. This patch fixup this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 812960ba95e1..16484060a24c 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -271,6 +271,8 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + usbhs_pkt_start(pipe); + return 0; } @@ -424,8 +426,7 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv, pipe = usbhsg_uep_to_pipe(uep); if (!pipe) { dev_err(dev, "wrong recip request\n"); - ret = -EINVAL; - goto usbhsg_recip_run_handle_end; + return -EINVAL; } switch (recip) { @@ -452,9 +453,6 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv, ret = func(priv, uep, ctrl); } -usbhsg_recip_run_handle_end: - usbhs_pkt_start(pipe); - return ret; } From 91b158f4d11164bfe5710873c8e162cf8c8d132b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:28:26 -0800 Subject: [PATCH 31/50] usb: renesas_usbhs: call usbhsg_queue_pop() when pipe disable. When poping packet from queue, it needs correct end procedure. This patch call usbhsg_queue_pop() in usbhsg_pipe_disable(). Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 16484060a24c..dba15e07fbd2 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -557,14 +557,16 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep) struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhs_pkt *pkt; - usbhs_pipe_disable(pipe); - while (1) { pkt = usbhs_pkt_pop(pipe, NULL); if (!pkt) break; + + usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET); } + usbhs_pipe_disable(pipe); + return 0; } From dfbb7f4fba47153de4be9ed6092804ebfd16bfbb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:28:35 -0800 Subject: [PATCH 32/50] usb: renesas_usbhs: add test-mode support Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 5 +++++ drivers/usb/renesas_usbhs/common.h | 2 ++ drivers/usb/renesas_usbhs/mod_gadget.c | 22 +++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 016a34f58523..32a879fb0e36 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -132,6 +132,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); } +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) +{ + usbhs_write(priv, TESTMODE, mode); +} + /* * frame functions */ diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 71c295c76d9e..d79b3e27db95 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -33,6 +33,7 @@ struct usbhs_priv; #define SYSCFG 0x0000 #define BUSWAIT 0x0002 #define DVSTCTR 0x0008 +#define TESTMODE 0x000C #define CFIFO 0x0014 #define CFIFOSEL 0x0020 #define CFIFOCTR 0x0022 @@ -283,6 +284,7 @@ void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); */ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode); /* * usb request diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dba15e07fbd2..1951de02957e 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -14,6 +14,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include #include #include #include @@ -286,6 +287,24 @@ struct usbhsg_recip_handle req_clear_feature = { /* * USB_TYPE_STANDARD / set feature functions */ +static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + switch (le16_to_cpu(ctrl->wValue)) { + case USB_DEVICE_TEST_MODE: + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + udelay(100); + usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8)); + break; + default: + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + break; + } + + return 0; +} + static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, struct usbhsg_uep *uep, struct usb_ctrlrequest *ctrl) @@ -301,7 +320,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, struct usbhsg_recip_handle req_set_feature = { .name = "set feature", - .device = usbhsg_recip_handler_std_control_done, + .device = usbhsg_recip_handler_std_set_device, .interface = usbhsg_recip_handler_std_control_done, .endpoint = usbhsg_recip_handler_std_set_endpoint, }; @@ -849,6 +868,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) gpriv->gadget.speed = USB_SPEED_UNKNOWN; /* disable sys */ + usbhs_sys_set_test_mode(priv, 0); usbhs_sys_function_ctrl(priv, 0); usbhsg_pipe_disable(dcp); From b294b203361d2cf5f006a0233d2065ed0e0b5b76 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Nov 2011 17:28:45 -0800 Subject: [PATCH 33/50] usb: renesas_usbhs: remove the_controller_link current renesas_usbhs is using new style udc_start/stop from af1d7056a5c1e5eaaf807ddd1423101db84668d0 (usb: gadget: renesas: convert to new style). with this patch we can finally remove the global "the_controller_link" Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 1951de02957e..cf3141c330a3 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -45,7 +45,6 @@ struct usbhsg_uep { struct usbhsg_gpriv { struct usb_gadget gadget; struct usbhs_mod mod; - struct list_head link; struct usbhsg_uep *uep; int uep_size; @@ -115,16 +114,6 @@ struct usbhsg_recip_handle { #define usbhsg_status_clr(gp, b) (gp->status &= ~b) #define usbhsg_status_has(gp, b) (gp->status & b) -/* controller */ -LIST_HEAD(the_controller_link); - -#define usbhsg_for_each_controller(gpriv)\ - list_for_each_entry(gpriv, &the_controller_link, link) -#define usbhsg_controller_register(gpriv)\ - list_add_tail(&(gpriv)->link, &the_controller_link) -#define usbhsg_controller_unregister(gpriv)\ - list_del_init(&(gpriv)->link) - /* * queue push/pop */ @@ -1032,8 +1021,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) } } - usbhsg_controller_register(gpriv); - ret = usb_add_gadget_udc(dev, &gpriv->gadget); if (ret) goto err_register; @@ -1062,8 +1049,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv) device_unregister(&gpriv->gadget.dev); - usbhsg_controller_unregister(gpriv); - kfree(gpriv->uep); kfree(gpriv); } From 9823a52539adce658f2414e33f2838b896ea4971 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Tue, 29 Nov 2011 22:08:00 +0100 Subject: [PATCH 34/50] usb: gadget: Use kcalloc instead of kzalloc to allocate array The advantage of kcalloc is, that will prevent integer overflows which could result from the multiplication of number of elements and size and it is also a bit nicer to read. The semantic patch that makes this change is available in https://lkml.org/lkml/2011/11/25/107 Signed-off-by: Thomas Meyer Acked-by: Michal Nazarewicz <[4]mina86@mina86.com> Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 2 +- drivers/usb/gadget/f_mass_storage.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index acb38004eec0..da9d04815ea5 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1408,7 +1408,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) ENTER(); count = ffs->eps_count; - epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL); + epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) return -ENOMEM; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 860e15ac8f24..a18ebeed82b5 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2775,7 +2775,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, * Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); + curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); if (unlikely(!curlun)) { rc = -ENOMEM; goto error_release; From 487d54d172b3afd3d2bf124b24eaf7f7e7b8a668 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 30 Nov 2011 09:57:13 +0800 Subject: [PATCH 35/50] usb: gadget: mv_udc: add otg relative code Add otg relative code, make it possible to switch between host and device. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc.h | 2 ++ drivers/usb/gadget/mv_udc_core.c | 33 +++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index daa75c12f336..b2c36ee3c82c 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -216,6 +216,8 @@ struct mv_udc { struct work_struct vbus_work; struct workqueue_struct *qwork; + struct otg_transceiver *transceiver; + struct mv_usb_platform_data *pdata; /* some SOC has mutiple clock sources for USB*/ diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 9376a7483c9b..647cc3ab1709 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1407,6 +1407,20 @@ static int mv_udc_start(struct usb_gadget_driver *driver, return retval; } + if (udc->transceiver) { + retval = otg_set_peripheral(udc->transceiver, &udc->gadget); + if (retval) { + dev_err(&udc->dev->dev, + "unable to register peripheral to otg\n"); + if (driver->unbind) { + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + } + return retval; + } + } + /* pullup is always on */ mv_udc_pullup(&udc->gadget, 1); @@ -2109,7 +2123,12 @@ static int __devexit mv_udc_remove(struct platform_device *dev) destroy_workqueue(udc->qwork); } - if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + /* + * If we have transceiver inited, + * then vbus irq will not be requested in udc driver. + */ + if (udc->pdata && udc->pdata->vbus + && udc->clock_gating && udc->transceiver == NULL) free_irq(udc->pdata->vbus->irq, &dev->dev); /* free memory allocated in probe */ @@ -2182,6 +2201,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev) udc->dev = dev; +#ifdef CONFIG_USB_OTG_UTILS + if (pdata->mode == MV_USB_MODE_OTG) + udc->transceiver = otg_get_transceiver(); +#endif + udc->clknum = pdata->clknum; for (clk_i = 0; clk_i < udc->clknum; clk_i++) { udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); @@ -2328,7 +2352,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) eps_init(udc); /* VBUS detect: we can disable/enable clock on demand.*/ - if (pdata->vbus) { + if (udc->transceiver) + udc->clock_gating = 1; + else if (pdata->vbus) { udc->clock_gating = 1; retval = request_threaded_irq(pdata->vbus->irq, NULL, mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); @@ -2371,7 +2397,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev) return 0; err_unregister: - if (udc->pdata && udc->pdata->vbus && udc->clock_gating) + if (udc->pdata && udc->pdata->vbus + && udc->clock_gating && udc->transceiver == NULL) free_irq(pdata->vbus->irq, &dev->dev); device_unregister(&udc->gadget.dev); err_free_irq: From 309d6d2be42c895c424a5090fcc2e95ce2d8499a Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 30 Nov 2011 09:57:14 +0800 Subject: [PATCH 36/50] usb: gadget: mv_udc: disable ISR when stopped When device is stopped, there is no need to handle ISR. Especially when otg switch to HOST mode. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc.h | 3 ++- drivers/usb/gadget/mv_udc_core.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index b2c36ee3c82c..3d8404484613 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -211,7 +211,8 @@ struct mv_udc { softconnected:1, force_fs:1, clock_gating:1, - active:1; + active:1, + stopped:1; /* stop bit is setted */ struct work_struct vbus_work; struct workqueue_struct *qwork; diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 647cc3ab1709..6ff0b6b238ac 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1056,6 +1056,8 @@ static void udc_stop(struct mv_udc *udc) USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN); writel(tmp, &udc->op_regs->usbintr); + udc->stopped = 1; + /* Reset the Run the bit in the command register to stop VUSB */ tmp = readl(&udc->op_regs->usbcmd); tmp &= ~USBCMD_RUN_STOP; @@ -1072,6 +1074,8 @@ static void udc_start(struct mv_udc *udc) /* Enable interrupts */ writel(usbintr, &udc->op_regs->usbintr); + udc->stopped = 0; + /* Set the Run bit in the command register */ writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd); } @@ -2040,6 +2044,10 @@ static irqreturn_t mv_udc_irq(int irq, void *dev) struct mv_udc *udc = (struct mv_udc *)dev; u32 status, intr; + /* Disable ISR when stopped bit is set */ + if (udc->stopped) + return IRQ_NONE; + spin_lock(&udc->lock); status = readl(&udc->op_regs->usbsts); From 85ff7bfb6e260d7cc6d675941f5569c9b7ad6b44 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 30 Nov 2011 09:57:15 +0800 Subject: [PATCH 37/50] usb: gadget: mv_udc: refine the clock relative code Split the clock relative code from clock gating solution. Then we can remove some duplicate code, make the code more clean. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 6ff0b6b238ac..77e906556378 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1138,11 +1138,11 @@ static int udc_reset(struct mv_udc *udc) return 0; } -static int mv_udc_enable(struct mv_udc *udc) +static int mv_udc_enable_internal(struct mv_udc *udc) { int retval; - if (udc->clock_gating == 0 || udc->active) + if (udc->active) return 0; dev_dbg(&udc->dev->dev, "enable udc\n"); @@ -1161,9 +1161,17 @@ static int mv_udc_enable(struct mv_udc *udc) return 0; } -static void mv_udc_disable(struct mv_udc *udc) +static int mv_udc_enable(struct mv_udc *udc) { - if (udc->clock_gating && udc->active) { + if (udc->clock_gating) + return mv_udc_enable_internal(udc); + + return 0; +} + +static void mv_udc_disable_internal(struct mv_udc *udc) +{ + if (udc->active) { dev_dbg(&udc->dev->dev, "disable udc\n"); if (udc->pdata->phy_deinit) udc->pdata->phy_deinit(udc->phy_regs); @@ -1172,6 +1180,12 @@ static void mv_udc_disable(struct mv_udc *udc) } } +static void mv_udc_disable(struct mv_udc *udc) +{ + if (udc->clock_gating) + mv_udc_disable_internal(udc); +} + static int mv_udc_get_frame(struct usb_gadget *gadget) { struct mv_udc *udc; @@ -2253,14 +2267,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) } /* we will acces controller register, so enable the clk */ - udc_clock_enable(udc); - if (pdata->phy_init) { - retval = pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&dev->dev, "phy init error %d\n", retval); - goto err_iounmap_phyreg; - } - } + retval = mv_udc_enable_internal(udc); + if (retval) + goto err_iounmap_phyreg; udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs + (readl(&udc->cap_regs->caplength_hciversion) @@ -2388,11 +2397,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) * If not, it means that VBUS detection is not supported, we * have to enable vbus active all the time to let controller work. */ - if (udc->clock_gating) { - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); - } else + if (udc->clock_gating) + mv_udc_disable_internal(udc); + else udc->vbus_active = 1; retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); @@ -2422,9 +2429,7 @@ err_free_dma: dma_free_coherent(&dev->dev, udc->ep_dqh_size, udc->ep_dqh, udc->ep_dqh_dma); err_disable_clock: - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); + mv_udc_disable_internal(udc); err_iounmap_phyreg: iounmap((void *)udc->phy_regs); err_iounmap_capreg: From 5076ae5588e53da32fef697f604fec33fe5fada0 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 30 Nov 2011 09:57:16 +0800 Subject: [PATCH 38/50] usb: gadget: mv_udc: refine suspend/resume function This patch impletments system suspend/resume functions for Marvell otg controller. If OTG is enabled, OTG driver will do most of the work. If not, we will check clock gating. If clock gating is enabled, the UDC will be start/stop automatically. If not, UDC will be start/stop in suspend/resume functions. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 47 ++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 77e906556378..143925c6a184 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -2447,7 +2447,30 @@ static int mv_udc_suspend(struct device *_dev) { struct mv_udc *udc = the_controller; - udc_stop(udc); + /* if OTG is enabled, the following will be done in OTG driver*/ + if (udc->transceiver) + return 0; + + if (udc->pdata->vbus && udc->pdata->vbus->poll) + if (udc->pdata->vbus->poll() == VBUS_HIGH) { + dev_info(&udc->dev->dev, "USB cable is connected!\n"); + return -EAGAIN; + } + + /* + * only cable is unplugged, udc can suspend. + * So do not care about clock_gating == 1. + */ + if (!udc->clock_gating) { + udc_stop(udc); + + spin_lock_irq(&udc->lock); + /* stop all usb activities */ + stop_activity(udc, udc->driver); + spin_unlock_irq(&udc->lock); + + mv_udc_disable_internal(udc); + } return 0; } @@ -2457,20 +2480,22 @@ static int mv_udc_resume(struct device *_dev) struct mv_udc *udc = the_controller; int retval; - if (udc->pdata->phy_init) { - retval = udc->pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&udc->dev->dev, - "init phy error %d when resume back\n", - retval); + /* if OTG is enabled, the following will be done in OTG driver*/ + if (udc->transceiver) + return 0; + + if (!udc->clock_gating) { + retval = mv_udc_enable_internal(udc); + if (retval) return retval; + + if (udc->driver && udc->softconnect) { + udc_reset(udc); + ep0_reset(udc); + udc_start(udc); } } - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - return 0; } From 2bcb75144027fcee878319de87a967a4dec49403 Mon Sep 17 00:00:00 2001 From: Neil Zhang Date: Wed, 30 Nov 2011 09:57:17 +0800 Subject: [PATCH 39/50] usb: gadget: mv_udc: replace some debug info replace some debug info, make it easy to use. Signed-off-by: Neil Zhang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_udc_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 143925c6a184..b229edeb2bb6 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1230,10 +1230,11 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); + udc->vbus_active = (is_active != 0); + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", __func__, udc->softconnect, udc->vbus_active); - udc->vbus_active = (is_active != 0); if (udc->driver && udc->softconnect && udc->vbus_active) { retval = mv_udc_enable(udc); if (retval == 0) { @@ -1262,10 +1263,11 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) udc = container_of(gadget, struct mv_udc, gadget); spin_lock_irqsave(&udc->lock, flags); + udc->softconnect = (is_on != 0); + dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", __func__, udc->softconnect, udc->vbus_active); - udc->softconnect = (is_on != 0); if (udc->driver && udc->softconnect && udc->vbus_active) { retval = mv_udc_enable(udc); if (retval == 0) { From 37332ee0dfb017aea566047be945d6fd3531c713 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:25:37 -0800 Subject: [PATCH 40/50] usb: renesas_usbhs: add lost error value when enqueue usbhsh_urb_enqueue() didn't have error value when usbhsh_device_attach() failed Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 182bdb8e45ec..c39404783271 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -760,8 +760,10 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, */ if (!usbhsh_usbv_to_udev(usbv)) { new_udev = usbhsh_device_attach(hpriv, urb); - if (!new_udev) + if (!new_udev) { + ret = -EIO; goto usbhsh_urb_enqueue_error_not_linked; + } } /* From 547965436d8dc8747b1931af954a178d30e86f6c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:26:07 -0800 Subject: [PATCH 41/50] usb: renesas_usbhs: pop packet when urb dequeued usbhsh_ureq_free() is not enough when urb dequeued. Without this patch, the driver can not recognize re-connected USB device after USB hub disconnected Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index c39404783271..0dbbc6613c1f 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -800,8 +800,13 @@ static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); - if (ureq) - usbhsh_ureq_free(hpriv, ureq); + if (ureq) { + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usbhs_pkt *pkt = &ureq->pkt; + + usbhs_pkt_pop(pkt->pipe, pkt); + usbhsh_queue_done(priv, pkt); + } return 0; } From c1e4877a4106a31319c4ad65b625c11393df98d6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:27:21 -0800 Subject: [PATCH 42/50] usb: renesas_usbhs: modify device attach method Current renesas_usbhs had been assigning udev to each urb. It was executed even though it was device0. For this reason, the device0 had to set the new device address which has still not been assigned. (it will be assigned on next step). Current renesas_usbhs used fixed address for it. but it is not good for USB hub support. This patch modifies this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 97 ++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 0dbbc6613c1f..164f28ee9610 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -220,10 +220,30 @@ static int usbhsh_device_has_endpoint(struct usbhsh_device *udev) return !list_empty(&udev->ep_list_head); } +static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, + struct urb *urb) +{ + struct usb_device *usbv = usbhsh_urb_to_usbv(urb); + struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + + /* usbhsh_device_attach() is still not called */ + if (!udev) + return NULL; + + /* if it is device0, return it */ + if (0 == usb_pipedevice(urb->pipe)) + return usbhsh_device0(hpriv); + + /* return attached device */ + return udev; +} + static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, struct urb *urb) { struct usbhsh_device *udev = NULL; + struct usbhsh_device *udev0 = usbhsh_device0(hpriv); + struct usbhsh_device *pos; struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); @@ -232,31 +252,29 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, u16 upphub, hubport; int i; + /* + * This function should be called only while urb is pointing to device0. + * It will attach unused usbhsh_device to urb (usbv), + * and initialize device0. + * You can use usbhsh_device_get() to get "current" udev, + * and usbhsh_usbv_to_udev() is for "attached" udev. + */ + if (0 != usb_pipedevice(urb->pipe)) { + dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); + return NULL; + } + /******************** spin lock ********************/ usbhs_lock(priv, flags); /* - * find device + * find unused device */ - if (0 == usb_pipedevice(urb->pipe)) { - /* - * device0 is special case - */ - udev = usbhsh_device0(hpriv); - if (usbhsh_udev_is_used(udev)) - udev = NULL; - } else { - struct usbhsh_device *pos; - - /* - * find unused device - */ - usbhsh_for_each_udev(pos, hpriv, i) { - if (usbhsh_udev_is_used(pos)) - continue; - udev = pos; - break; - } + usbhsh_for_each_udev(pos, hpriv, i) { + if (usbhsh_udev_is_used(pos)) + continue; + udev = pos; + break; } if (udev) { @@ -280,9 +298,22 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, if (usbhsh_device_has_endpoint(udev)) dev_warn(dev, "udev have old endpoint\n"); + if (usbhsh_device_has_endpoint(udev0)) + dev_warn(dev, "udev0 have old endpoint\n"); + /* uep will be attached */ + INIT_LIST_HEAD(&udev0->ep_list_head); INIT_LIST_HEAD(&udev->ep_list_head); + /* + * set device0 config + */ + usbhs_set_device_config(priv, + 0, 0, 0, usbv->speed); + + /* + * set new device config + */ upphub = 0; hubport = 0; if (!usbhsh_connected_to_rhdev(hcd, udev)) { @@ -296,7 +327,6 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, upphub, hubport, parent); } - /* set device config */ usbhs_set_device_config(priv, usbhsh_device_number(hpriv, udev), upphub, hubport, usbv->speed); @@ -322,6 +352,15 @@ static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, if (usbhsh_device_has_endpoint(udev)) dev_warn(dev, "udev still have endpoint\n"); + /* + * There is nothing to do if it is device0. + * see + * usbhsh_device_attach() + * usbhsh_device_get() + */ + if (0 == usbhsh_device_number(hpriv, udev)) + return; + /******************** spin lock ********************/ usbhs_lock(priv, flags); @@ -345,8 +384,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, gfp_t mem_flags) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usb_device *usbv = usbhsh_urb_to_usbv(urb); - struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); struct usb_host_endpoint *ep = urb->ep; struct usbhsh_ep *uep; struct usbhsh_pipe_info *info; @@ -577,11 +615,15 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, /* * renesas_usbhs can not use original usb address. * see HARDWARE LIMITATION. - * modify usb address here. + * modify usb address here to use attached device. + * see usbhsh_device_attach() */ if (usbhsh_is_request_address(urb)) { - /* FIXME */ - req.wValue = 1; + struct usb_device *usbv = usbhsh_urb_to_usbv(urb); + struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); + + /* udev is a attached device */ + req.wValue = usbhsh_device_number(hpriv, udev); dev_dbg(dev, "create new address - %d\n", req.wValue); } @@ -742,7 +784,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, 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); - struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usb_host_endpoint *ep = urb->ep; struct usbhsh_device *new_udev = NULL; int is_dir_in = usb_pipein(urb->pipe); @@ -758,7 +799,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, /* * attach udev if needed */ - if (!usbhsh_usbv_to_udev(usbv)) { + if (!usbhsh_device_get(hpriv, urb)) { new_udev = usbhsh_device_attach(hpriv, urb); if (!new_udev) { ret = -EIO; From e4c57ded48d9bad95a4d7254e75a81f7abcffef9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:27:49 -0800 Subject: [PATCH 43/50] usb: renesas_usbhs: add usbhsh_endpoint_detach_all() for error case This patch adds usbhsh_endpoint_detach_all() for error case. usbhs_endpoitn_xxx() functions were moved to upper side in source code. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 302 +++++++++++++++------------ 1 file changed, 163 insertions(+), 139 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 164f28ee9610..5b6ae2a8d303 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -84,6 +84,7 @@ struct usbhsh_device { struct usbhsh_ep { struct usbhs_pipe *pipe; struct usbhsh_device *udev; /* attached udev */ + struct usb_host_endpoint *ep; struct list_head ep_list; /* list to usbhsh_device */ int maxp; @@ -147,6 +148,8 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_ep_to_uep(u) ((u)->hcpriv) #define usbhsh_uep_to_pipe(u) ((u)->pipe) #define usbhsh_uep_to_udev(u) ((u)->udev) +#define usbhsh_uep_to_ep(u) ((u)->ep) + #define usbhsh_urb_to_ureq(u) ((u)->hcpriv) #define usbhsh_urb_to_usbv(u) ((u)->dev) @@ -204,6 +207,157 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, kfree(ureq); } +/* + * end-point control + */ +static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, + struct urb *urb); +static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, + struct urb *urb, + gfp_t mem_flags) +{ + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); + struct usb_host_endpoint *ep = urb->ep; + struct usbhsh_ep *uep; + struct usbhsh_pipe_info *info; + struct usbhs_pipe *best_pipe = NULL; + struct device *dev = usbhs_priv_to_dev(priv); + struct usb_endpoint_descriptor *desc = &ep->desc; + unsigned long flags; + + uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); + if (!uep) { + dev_err(dev, "usbhsh_ep alloc fail\n"); + return -ENOMEM; + } + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + /* + * find best pipe for endpoint + * see + * HARDWARE LIMITATION + */ + if (usb_endpoint_xfer_control(desc)) { + /* best pipe is DCP */ + best_pipe = usbhsh_hpriv_to_dcp(hpriv); + } else { + struct usbhs_pipe *pipe; + unsigned int min_usr = ~0; + int dir_in_req = !!usb_pipein(urb->pipe); + int i, dir_in; + + usbhs_for_each_pipe(pipe, priv, i) { + if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) + continue; + + dir_in = !!usbhs_pipe_is_dir_in(pipe); + if (0 != (dir_in - dir_in_req)) + continue; + + info = usbhsh_pipe_info(pipe); + if (min_usr > info->usr_cnt) { + min_usr = info->usr_cnt; + best_pipe = pipe; + } + } + } + + if (best_pipe) { + /* update pipe user count */ + info = usbhsh_pipe_info(best_pipe); + info->usr_cnt++; + + /* init this endpoint, and attach it to udev */ + INIT_LIST_HEAD(&uep->ep_list); + list_add_tail(&uep->ep_list, &udev->ep_list_head); + } + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + if (unlikely(!best_pipe)) { + dev_err(dev, "couldn't find best pipe\n"); + kfree(uep); + return -EIO; + } + + /* + * init uep + */ + uep->pipe = best_pipe; + uep->maxp = usb_endpoint_maxp(desc); + usbhsh_uep_to_udev(uep) = udev; + usbhsh_uep_to_ep(uep) = ep; + usbhsh_ep_to_uep(ep) = uep; + + /* + * usbhs_pipe_config_update() should be called after + * usbhs_set_device_config() + * see + * DCPMAXP/PIPEMAXP + */ + usbhs_pipe_sequence_data0(uep->pipe); + usbhs_pipe_config_update(uep->pipe, + usbhsh_device_number(hpriv, udev), + usb_endpoint_num(desc), + uep->maxp); + + dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, + usbhsh_device_number(hpriv, udev), + usbhs_pipe_name(uep->pipe), uep); + + return 0; +} + +static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, + struct usb_host_endpoint *ep) +{ + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct device *dev = usbhs_priv_to_dev(priv); + struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); + struct usbhsh_pipe_info *info; + unsigned long flags; + + if (!uep) + return; + + dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, + usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), + usbhs_pipe_name(uep->pipe), uep); + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + info = usbhsh_pipe_info(uep->pipe); + info->usr_cnt--; + + /* remove this endpoint from udev */ + list_del_init(&uep->ep_list); + + uep->pipe = NULL; + uep->maxp = 0; + usbhsh_uep_to_udev(uep) = NULL; + usbhsh_uep_to_ep(uep) = NULL; + usbhsh_ep_to_uep(ep) = NULL; + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + kfree(uep); +} + +static void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv, + struct usbhsh_device *udev) +{ + struct usbhsh_ep *uep, *next; + + list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list) + usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep)); +} + /* * device control */ @@ -295,11 +449,15 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, return NULL; } - if (usbhsh_device_has_endpoint(udev)) + if (usbhsh_device_has_endpoint(udev)) { dev_warn(dev, "udev have old endpoint\n"); + usbhsh_endpoint_detach_all(hpriv, udev); + } - if (usbhsh_device_has_endpoint(udev0)) + if (usbhsh_device_has_endpoint(udev0)) { dev_warn(dev, "udev0 have old endpoint\n"); + usbhsh_endpoint_detach_all(hpriv, udev0); + } /* uep will be attached */ INIT_LIST_HEAD(&udev0->ep_list_head); @@ -349,8 +507,10 @@ static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); - if (usbhsh_device_has_endpoint(udev)) + if (usbhsh_device_has_endpoint(udev)) { dev_warn(dev, "udev still have endpoint\n"); + usbhsh_endpoint_detach_all(hpriv, udev); + } /* * There is nothing to do if it is device0. @@ -376,142 +536,6 @@ static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, /******************** spin unlock ******************/ } -/* - * end-point control - */ -static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); - struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_ep *uep; - struct usbhsh_pipe_info *info; - struct usbhs_pipe *best_pipe = NULL; - struct device *dev = usbhs_priv_to_dev(priv); - struct usb_endpoint_descriptor *desc = &ep->desc; - unsigned long flags; - - uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); - if (!uep) { - dev_err(dev, "usbhsh_ep alloc fail\n"); - return -ENOMEM; - } - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - /* - * find best pipe for endpoint - * see - * HARDWARE LIMITATION - */ - if (usb_endpoint_xfer_control(desc)) { - /* best pipe is DCP */ - best_pipe = usbhsh_hpriv_to_dcp(hpriv); - } else { - struct usbhs_pipe *pipe; - unsigned int min_usr = ~0; - int dir_in_req = !!usb_pipein(urb->pipe); - int i, dir_in; - - usbhs_for_each_pipe(pipe, priv, i) { - if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) - continue; - - dir_in = !!usbhs_pipe_is_dir_in(pipe); - if (0 != (dir_in - dir_in_req)) - continue; - - info = usbhsh_pipe_info(pipe); - if (min_usr > info->usr_cnt) { - min_usr = info->usr_cnt; - best_pipe = pipe; - } - } - } - - if (best_pipe) { - /* update pipe user count */ - info = usbhsh_pipe_info(best_pipe); - info->usr_cnt++; - - /* init this endpoint, and attach it to udev */ - INIT_LIST_HEAD(&uep->ep_list); - list_add_tail(&uep->ep_list, &udev->ep_list_head); - } - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - if (unlikely(!best_pipe)) { - dev_err(dev, "couldn't find best pipe\n"); - kfree(uep); - return -EIO; - } - - /* - * init uep - */ - uep->pipe = best_pipe; - uep->maxp = usb_endpoint_maxp(desc); - usbhsh_uep_to_udev(uep) = udev; - usbhsh_ep_to_uep(ep) = uep; - - /* - * usbhs_pipe_config_update() should be called after - * usbhs_set_device_config() - * see - * DCPMAXP/PIPEMAXP - */ - usbhs_pipe_sequence_data0(uep->pipe); - usbhs_pipe_config_update(uep->pipe, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc), - uep->maxp); - - dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, - usbhsh_device_number(hpriv, udev), - usbhs_pipe_name(uep->pipe), uep); - - return 0; -} - -static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, - struct usb_host_endpoint *ep) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); - struct usbhsh_pipe_info *info; - unsigned long flags; - - if (!uep) - return; - - dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, - usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), - usbhs_pipe_name(uep->pipe), uep); - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - info = usbhsh_pipe_info(uep->pipe); - info->usr_cnt--; - - /* remove this endpoint from udev */ - list_del_init(&uep->ep_list); - - usbhsh_uep_to_udev(uep) = NULL; - usbhsh_ep_to_uep(ep) = NULL; - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - kfree(uep); -} - /* * queue push/pop */ From e5679d07a6ca5512070fb5e65dcc66eeb5087d0d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:28:24 -0800 Subject: [PATCH 44/50] usb: renesas_usbhs: add usbhs_pipe_attach() method driver has to re-use the limited pipe for each device/endpoint when it is USB host hub mode, since number of pipe has limitation. This patch adds usbhsh_pipe_attach/detach() functions for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 300 +++++++++++++++------------ 1 file changed, 172 insertions(+), 128 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 5b6ae2a8d303..c7f9be9f5c17 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -45,32 +45,31 @@ * * +--------+ pipes are reused for each uep. * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when - * +--------+ | | target device was changed + * +--------+ | | other device requested * +- [uep 1 (bulk)] --|---+ +--------------+ * | +--------------> | pipe0 (dcp) | - * +- [uep 2 (bulk)] --|---|---+ +--------------+ - * | | | | pipe1 (isoc) | - * +--------+ | | | +--------------+ - * | udev 2 |-+- [uep 0 (dcp) ] --+ +-- |------> | pipe2 (bulk) | - * +--------+ | | | | +--------------+ - * +- [uep 1 (int) ] --|-+ | +------> | pipe3 (bulk) | - * | | | | +--------------+ - * +--------+ | +-|---|------> | pipe4 (int) | - * | udev 3 |-+- [uep 0 (dcp) ] --+ | | +--------------+ - * +--------+ | | | | .... | - * +- [uep 1 (bulk)] ------+ | | .... | + * +- [uep 2 (bulk)] -@ | +--------------+ + * | | pipe1 (isoc) | + * +--------+ | +--------------+ + * | udev 2 |-+- [uep 0 (dcp) ] -@ +----------> | pipe2 (bulk) | + * +--------+ | +--------------+ + * +- [uep 1 (int) ] ----+ +------> | pipe3 (bulk) | + * | | +--------------+ + * +--------+ +-----|------> | pipe4 (int) | + * | udev 3 |-+- [uep 0 (dcp) ] -@ | +--------------+ + * +--------+ | | | .... | + * +- [uep 1 (bulk)] -@ | | .... | * | | * +- [uep 2 (bulk)]-----------+ + * + * @ : uep requested free pipe, but all have been used. + * now it is waiting for free pipe */ /* * struct */ -struct usbhsh_pipe_info { - unsigned int usr_cnt; /* see usbhsh_endpoint_alloc() */ -}; - struct usbhsh_request { struct urb *urb; struct usbhs_pkt pkt; @@ -82,12 +81,10 @@ struct usbhsh_device { }; struct usbhsh_ep { - struct usbhs_pipe *pipe; + struct usbhs_pipe *pipe; /* attached pipe */ struct usbhsh_device *udev; /* attached udev */ struct usb_host_endpoint *ep; struct list_head ep_list; /* list to usbhsh_device */ - - int maxp; }; #define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ @@ -98,9 +95,6 @@ struct usbhsh_hpriv { struct usbhsh_device udev[USBHSH_DEVICE_MAX]; - struct usbhsh_pipe_info *pipe_info; - int pipe_size; - u32 port_stat; /* USB_PORT_STAT_xxx */ struct completion setup_ack_done; @@ -115,17 +109,6 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_priv_to_hpriv(priv) \ container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) -#define __usbhsh_for_each_hpipe(start, pos, h, i) \ - for (i = start, pos = (h)->hpipe + i; \ - i < (h)->hpipe_size; \ - i++, pos = (h)->hpipe + i) - -#define usbhsh_for_each_hpipe(pos, hpriv, i) \ - __usbhsh_for_each_hpipe(1, pos, hpriv, i) - -#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i) \ - __usbhsh_for_each_hpipe(0, pos, hpriv, i) - #define __usbhsh_for_each_udev(start, pos, h, i) \ for (i = start, pos = (h)->udev + i; \ i < USBHSH_DEVICE_MAX; \ @@ -158,7 +141,7 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host"; #define usbhsh_udev_to_usbv(h) ((h)->usbv) #define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h) -#define usbhsh_pipe_info(p) ((p)->mod_private) +#define usbhsh_pipe_to_uep(p) ((p)->mod_private) #define usbhsh_device_parent(d) (usbhsh_usbv_to_udev((d)->usbv->parent)) #define usbhsh_device_hubport(d) ((d)->usbv->portnum) @@ -208,10 +191,129 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, } /* - * end-point control + * pipe control */ static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, struct urb *urb); + +static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, + struct urb *urb) +{ + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); + struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); + struct usbhs_pipe *pipe; + struct usb_endpoint_descriptor *desc = &urb->ep->desc; + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + int dir_in_req = !!usb_pipein(urb->pipe); + int is_dcp = usb_endpoint_xfer_control(desc); + int i, dir_in; + int ret = -EBUSY; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + if (unlikely(usbhsh_uep_to_pipe(uep))) { + dev_err(dev, "uep already has pipe\n"); + goto usbhsh_pipe_attach_done; + } + + usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + + /* check pipe type */ + if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) + continue; + + /* check pipe direction if normal pipe */ + if (!is_dcp) { + dir_in = !!usbhs_pipe_is_dir_in(pipe); + if (0 != (dir_in - dir_in_req)) + continue; + } + + /* check pipe is free */ + if (usbhsh_pipe_to_uep(pipe)) + continue; + + /* + * attach pipe to uep + * + * usbhs_pipe_config_update() should be called after + * usbhs_set_device_config() + * see + * DCPMAXP/PIPEMAXP + */ + usbhsh_uep_to_pipe(uep) = pipe; + usbhsh_pipe_to_uep(pipe) = uep; + + if (!usb_gettoggle(urb->dev, + usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe))) { + usbhs_pipe_sequence_data0(pipe); + usb_settoggle(urb->dev, + usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), 1); + } + + usbhs_pipe_config_update(pipe, + usbhsh_device_number(hpriv, udev), + usb_endpoint_num(desc), + usb_endpoint_maxp(desc)); + + dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__, + usbhsh_device_number(hpriv, udev), + usb_endpoint_num(desc), + usbhs_pipe_name(pipe), + dir_in_req ? "in" : "out"); + + ret = 0; + break; + } + +usbhsh_pipe_attach_done: + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + return ret; +} + +static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, + struct usbhsh_ep *uep) +{ + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usbhs_pipe *pipe; + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + pipe = usbhsh_uep_to_pipe(uep); + + if (unlikely(!pipe)) { + dev_err(dev, "uep doens't have pipe\n"); + } else { + struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); + struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); + + /* detach pipe from uep */ + usbhsh_uep_to_pipe(uep) = NULL; + usbhsh_pipe_to_uep(pipe) = NULL; + + dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__, + usbhsh_device_number(hpriv, udev), + usb_endpoint_num(&ep->desc), + usbhs_pipe_name(pipe)); + } + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ +} + +/* + * endpoint control + */ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, struct urb *urb, gfp_t mem_flags) @@ -220,8 +322,6 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); struct usb_host_endpoint *ep = urb->ep; struct usbhsh_ep *uep; - struct usbhsh_pipe_info *info; - struct usbhs_pipe *best_pipe = NULL; struct device *dev = usbhs_priv_to_dev(priv); struct usb_endpoint_descriptor *desc = &ep->desc; unsigned long flags; @@ -236,78 +336,21 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, usbhs_lock(priv, flags); /* - * find best pipe for endpoint - * see - * HARDWARE LIMITATION + * init endpoint */ - if (usb_endpoint_xfer_control(desc)) { - /* best pipe is DCP */ - best_pipe = usbhsh_hpriv_to_dcp(hpriv); - } else { - struct usbhs_pipe *pipe; - unsigned int min_usr = ~0; - int dir_in_req = !!usb_pipein(urb->pipe); - int i, dir_in; + INIT_LIST_HEAD(&uep->ep_list); + list_add_tail(&uep->ep_list, &udev->ep_list_head); - usbhs_for_each_pipe(pipe, priv, i) { - if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) - continue; - - dir_in = !!usbhs_pipe_is_dir_in(pipe); - if (0 != (dir_in - dir_in_req)) - continue; - - info = usbhsh_pipe_info(pipe); - if (min_usr > info->usr_cnt) { - min_usr = info->usr_cnt; - best_pipe = pipe; - } - } - } - - if (best_pipe) { - /* update pipe user count */ - info = usbhsh_pipe_info(best_pipe); - info->usr_cnt++; - - /* init this endpoint, and attach it to udev */ - INIT_LIST_HEAD(&uep->ep_list); - list_add_tail(&uep->ep_list, &udev->ep_list_head); - } - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - if (unlikely(!best_pipe)) { - dev_err(dev, "couldn't find best pipe\n"); - kfree(uep); - return -EIO; - } - - /* - * init uep - */ - uep->pipe = best_pipe; - uep->maxp = usb_endpoint_maxp(desc); usbhsh_uep_to_udev(uep) = udev; usbhsh_uep_to_ep(uep) = ep; usbhsh_ep_to_uep(ep) = uep; - /* - * usbhs_pipe_config_update() should be called after - * usbhs_set_device_config() - * see - * DCPMAXP/PIPEMAXP - */ - usbhs_pipe_sequence_data0(uep->pipe); - usbhs_pipe_config_update(uep->pipe, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc), - uep->maxp); + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ - dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, + dev_dbg(dev, "%s [%d-%d]\n", __func__, usbhsh_device_number(hpriv, udev), - usbhs_pipe_name(uep->pipe), uep); + usb_endpoint_num(desc)); return 0; } @@ -318,27 +361,24 @@ static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); struct device *dev = usbhs_priv_to_dev(priv); struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); - struct usbhsh_pipe_info *info; unsigned long flags; if (!uep) return; - dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, + dev_dbg(dev, "%s [%d-%d]\n", __func__, usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), - usbhs_pipe_name(uep->pipe), uep); + usb_endpoint_num(&ep->desc)); + + if (usbhsh_uep_to_pipe(uep)) + usbhsh_pipe_detach(hpriv, uep); /******************** spin lock ********************/ usbhs_lock(priv, flags); - info = usbhsh_pipe_info(uep->pipe); - info->usr_cnt--; - /* remove this endpoint from udev */ list_del_init(&uep->ep_list); - uep->pipe = NULL; - uep->maxp = 0; usbhsh_uep_to_udev(uep) = NULL; usbhsh_uep_to_ep(uep) = NULL; usbhsh_ep_to_uep(ep) = NULL; @@ -545,6 +585,7 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct urb *urb = ureq->urb; + struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); struct device *dev = usbhs_priv_to_dev(priv); dev_dbg(dev, "%s\n", __func__); @@ -559,6 +600,8 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) usb_hcd_unlink_urb_from_ep(hcd, urb); usb_hcd_giveback_urb(hcd, urb, 0); + + usbhsh_pipe_detach(hpriv, uep); } static int usbhsh_queue_push(struct usb_hcd *hcd, @@ -811,7 +854,7 @@ 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"); @@ -822,6 +865,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, /* * attach udev if needed + * see [image of mod_host] */ if (!usbhsh_device_get(hpriv, urb)) { new_udev = usbhsh_device_attach(hpriv, urb); @@ -833,6 +877,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, /* * attach endpoint if needed + * see [image of mod_host] */ if (!usbhsh_ep_to_uep(ep)) { ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); @@ -840,6 +885,20 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, goto usbhsh_urb_enqueue_error_free_device; } + /* + * 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; + } + if (ret < 0) + goto usbhsh_urb_enqueue_error_free_endpoint; + /* * push packet */ @@ -850,6 +909,8 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, return ret; +usbhsh_urb_enqueue_error_free_endpoint: + usbhsh_endpoint_detach(hpriv, ep); usbhsh_urb_enqueue_error_free_device: if (new_udev) usbhsh_device_detach(hpriv, new_udev); @@ -1192,7 +1253,6 @@ static int usbhsh_irq_setup_err(struct usbhs_priv *priv, static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) { struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info; struct usbhs_pipe *pipe; u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); int pipe_size = usbhs_get_dparam(priv, pipe_size); @@ -1201,7 +1261,6 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) /* init all pipe */ old_type = USB_ENDPOINT_XFER_CONTROL; for (i = 0; i < pipe_size; i++) { - pipe_info[i].usr_cnt = 0; /* * data "output" will be finished as soon as possible, @@ -1235,7 +1294,7 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) dir_in); } - pipe->mod_private = pipe_info + i; + pipe->mod_private = NULL; } } @@ -1312,10 +1371,8 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) { struct usbhsh_hpriv *hpriv; struct usb_hcd *hcd; - struct usbhsh_pipe_info *pipe_info; struct usbhsh_device *udev; struct device *dev = usbhs_priv_to_dev(priv); - int pipe_size = usbhs_get_dparam(priv, pipe_size); int i; /* initialize hcd */ @@ -1325,12 +1382,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) return -ENOMEM; } - pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL); - if (!pipe_info) { - dev_err(dev, "Could not allocate pipe_info\n"); - goto usbhs_mod_host_probe_err; - } - /* * CAUTION * @@ -1350,8 +1401,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) hpriv->mod.name = "host"; hpriv->mod.start = usbhsh_start; hpriv->mod.stop = usbhsh_stop; - hpriv->pipe_info = pipe_info; - hpriv->pipe_size = pipe_size; usbhsh_port_stat_init(hpriv); /* init all device */ @@ -1363,11 +1412,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) dev_info(dev, "host probed\n"); return 0; - -usbhs_mod_host_probe_err: - usb_put_hcd(hcd); - - return -ENOMEM; } int usbhs_mod_host_remove(struct usbhs_priv *priv) From 3edeee3893b107364fe4ed8535245773b1e1e72b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:28:54 -0800 Subject: [PATCH 45/50] usb: renesas_usbhs: care pipe sequence driver has to re-use the limited pipe for each device/endpoint when it is USB host hub mode, since number of pipe has limitation. Then, each pipe should care own pipe sequence for next packet. This patch adds sequence control. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/fifo.c | 9 +++- drivers/usb/renesas_usbhs/fifo.h | 3 +- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- drivers/usb/renesas_usbhs/mod_host.c | 71 ++++++++++++++++++++------ drivers/usb/renesas_usbhs/pipe.c | 21 +++++++- 5 files changed, 86 insertions(+), 20 deletions(-) diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index ffdf5d15085e..b51fcd80d244 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -56,7 +56,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = { 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) + 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); @@ -90,6 +90,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, pkt->zero = zero; pkt->actual = 0; pkt->done = done; + pkt->sequence = sequence; usbhs_unlock(priv, flags); /******************** spin unlock ******************/ @@ -481,6 +482,9 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) int i, ret, len; int is_short; + usbhs_pipe_data_sequence(pipe, pkt->sequence); + pkt->sequence = -1; /* -1 sequence will be ignored */ + ret = usbhsf_fifo_select(pipe, fifo, 1); if (ret < 0) return 0; @@ -584,6 +588,8 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) /* * pipe enable to prepare packet receive */ + usbhs_pipe_data_sequence(pipe, pkt->sequence); + pkt->sequence = -1; /* -1 sequence will be ignored */ usbhs_pipe_enable(pipe); usbhsf_rx_irq_ctrl(pipe, 1); @@ -641,6 +647,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" */ if (0 == rcv_len) { + pkt->zero = 1; usbhsf_fifo_clear(pipe, fifo); goto usbhs_fifo_read_end; } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index 32a7b246b28d..f68609c0f489 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -59,6 +59,7 @@ struct usbhs_pkt { int trans; int actual; int zero; + int sequence; }; struct usbhs_pkt_handle { @@ -95,7 +96,7 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt); 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); + void *buf, int len, int zero, int sequence); struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); void usbhs_pkt_start(struct usbhs_pipe *pipe); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index cf3141c330a3..db2a1c6a0866 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -154,7 +154,7 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, req->actual = 0; req->status = -EINPROGRESS; usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, - req->buf, req->length, req->zero); + req->buf, req->length, req->zero, -1); usbhs_pkt_start(pipe); dev_dbg(dev, "pipe %d : queue push (%d)\n", diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index c7f9be9f5c17..72ee8e55e717 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -193,6 +193,48 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, /* * pipe control */ +static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv, + struct urb *urb, + struct usbhs_pkt *pkt) +{ + int len = urb->actual_length; + int maxp = usb_endpoint_maxp(&urb->ep->desc); + int t = 0; + + /* DCP is out of sequence control */ + if (usb_pipecontrol(urb->pipe)) + return; + + /* + * renesas_usbhs pipe has a limitation in a number. + * So, driver should re-use the limited pipe for each device/endpoint. + * DATA0/1 sequence should be saved for it. + * see [image of mod_host] + * [HARDWARE LIMITATION] + */ + + /* + * next sequence depends on actual_length + * + * ex) actual_length = 1147, maxp = 512 + * data0 : 512 + * data1 : 512 + * data0 : 123 + * data1 is the next sequence + */ + t = len / maxp; + if (len % maxp) + t++; + if (pkt->zero) + t++; + t %= 2; + + if (t) + usb_dotoggle(urb->dev, + usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); +} + static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, struct urb *urb); @@ -247,15 +289,6 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, usbhsh_uep_to_pipe(uep) = pipe; usbhsh_pipe_to_uep(pipe) = uep; - if (!usb_gettoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe))) { - usbhs_pipe_sequence_data0(pipe); - usb_settoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 1); - } - usbhs_pipe_config_update(pipe, usbhsh_device_number(hpriv, udev), usb_endpoint_num(desc), @@ -598,10 +631,11 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) urb->actual_length = pkt->actual; usbhsh_ureq_free(hpriv, ureq); + usbhsh_endpoint_sequence_save(hpriv, urb, pkt); + usbhsh_pipe_detach(hpriv, uep); + usb_hcd_unlink_urb_from_ep(hcd, urb); usb_hcd_giveback_urb(hcd, urb, 0); - - usbhsh_pipe_detach(hpriv, uep); } static int usbhsh_queue_push(struct usb_hcd *hcd, @@ -614,7 +648,7 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, struct device *dev = usbhsh_hcd_to_dev(hcd); struct usbhsh_request *ureq; void *buf; - int len; + int len, sequence; if (usb_pipeisoc(urb->pipe)) { dev_err(dev, "pipe iso is not supported now\n"); @@ -636,9 +670,15 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, buf = (void *)(urb->transfer_buffer + urb->actual_length); len = urb->transfer_buffer_length - urb->actual_length; + sequence = usb_gettoggle(urb->dev, + usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); + dev_dbg(dev, "%s\n", __func__); usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, - buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); + buf, len, (urb->transfer_flags & URB_ZERO_PACKET), + sequence); + usbhs_pkt_start(pipe); return 0; @@ -741,7 +781,8 @@ static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, usbhsh_data_stage_packet_done, urb->transfer_buffer, urb->transfer_buffer_length, - (urb->transfer_flags & URB_ZERO_PACKET)); + (urb->transfer_flags & URB_ZERO_PACKET), + -1); return 0; } @@ -770,7 +811,7 @@ static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, usbhsh_queue_done, NULL, urb->transfer_buffer_length, - 0); + 0, -1); return 0; } diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c36ad4c3a259..c2559e80d41f 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -478,10 +478,27 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) return usbhsp_flags_has(pipe, IS_DIR_HOST); } -void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data) +void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) { u16 mask = (SQCLR | SQSET); - u16 val = (data) ? SQSET : SQCLR; + u16 val; + + /* + * sequence + * 0 : data0 + * 1 : data1 + * -1 : no change + */ + switch (sequence) { + case 0: + val = SQCLR; + break; + case 1: + val = SQSET; + break; + default: + return; + } usbhsp_pipectrl_set(pipe, mask, val); } From 31e00fd116cab296da2d12bc0b82a30a9fbdd681 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:29:22 -0800 Subject: [PATCH 46/50] usb: renesas_usbhs: disable attch irq after device attached attch interrupt might happen infinitely on some USB hub (self power?). This patch disable attch irq after device attached, and enable it again when detach irq happen. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 72ee8e55e717..c947d0aca9bf 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1245,6 +1245,14 @@ static int usbhsh_irq_attch(struct usbhs_priv *priv, usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION); usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); + /* + * attch interrupt might happen infinitely on some device + * (on self power USB hub ?) + * disable it here. + */ + hpriv->mod.irq_attch = NULL; + usbhs_irq_callback_update(priv, &hpriv->mod); + return 0; } @@ -1259,6 +1267,12 @@ static int usbhsh_irq_dtch(struct usbhs_priv *priv, usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION); usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); + /* + * enable attch interrupt again + */ + hpriv->mod.irq_attch = usbhsh_irq_attch; + usbhs_irq_callback_update(priv, &hpriv->mod); + return 0; } From b1930da08872f6e17b8cdca60ee9c7321a8b5b8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:30:23 -0800 Subject: [PATCH 47/50] usb: renesas_usbhs: add usbhsh_is_running() It is possible to judge whether renesas_usbhs driver is running, by checking attch irq mask. This patch adds usbhsh_is_running() to check it. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index c947d0aca9bf..28b2cb3a029a 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -190,6 +190,21 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, kfree(ureq); } +/* + * status + */ +static int usbhsh_is_running(struct usbhsh_hpriv *hpriv) +{ + /* + * we can decide some device is attached or not + * by checking mod.irq_attch + * see + * usbhsh_irq_attch() + * usbhsh_irq_dtch() + */ + return (hpriv->mod.irq_attch == NULL); +} + /* * pipe control */ @@ -900,6 +915,11 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); + if (!usbhsh_is_running(hpriv)) { + ret = -EIO; + goto usbhsh_urb_enqueue_error_not_linked; + } + ret = usb_hcd_link_urb_to_ep(hcd, urb); if (ret) goto usbhsh_urb_enqueue_error_not_linked; @@ -1249,6 +1269,12 @@ static int usbhsh_irq_attch(struct usbhs_priv *priv, * attch interrupt might happen infinitely on some device * (on self power USB hub ?) * disable it here. + * + * usbhsh_is_running() becomes effective + * according to this process. + * see + * usbhsh_is_running() + * usbhsh_urb_enqueue() */ hpriv->mod.irq_attch = NULL; usbhs_irq_callback_update(priv, &hpriv->mod); @@ -1269,6 +1295,12 @@ static int usbhsh_irq_dtch(struct usbhs_priv *priv, /* * enable attch interrupt again + * + * usbhsh_is_running() becomes invalid + * according to this process. + * see + * usbhsh_is_running() + * usbhsh_urb_enqueue() */ hpriv->mod.irq_attch = usbhsh_irq_attch; usbhs_irq_callback_update(priv, &hpriv->mod); From 6d0376f84446507d07ae83935cbe7538d07c352f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:31:11 -0800 Subject: [PATCH 48/50] usb: renesas_usbhs: care usb_hcd_giveback_urb() status Without this patch, USB host hub shows error when cable was detached Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 28b2cb3a029a..9715a7013734 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -635,6 +635,7 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) struct urb *urb = ureq->urb; struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); struct device *dev = usbhs_priv_to_dev(priv); + int status = 0; dev_dbg(dev, "%s\n", __func__); @@ -643,6 +644,9 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) return; } + if (!usbhsh_is_running(hpriv)) + status = -ESHUTDOWN; + urb->actual_length = pkt->actual; usbhsh_ureq_free(hpriv, ureq); @@ -650,7 +654,7 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) usbhsh_pipe_detach(hpriv, uep); usb_hcd_unlink_urb_from_ep(hcd, urb); - usb_hcd_giveback_urb(hcd, urb, 0); + usb_hcd_giveback_urb(hcd, urb, status); } static int usbhsh_queue_push(struct usb_hcd *hcd, From 2d833faad260ad074fb1ed0a378f4ccd1b8025b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:31:37 -0800 Subject: [PATCH 49/50] usb: renesas_usbhs: add force packet remove method Packet should be force removed when reset/detach Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 9715a7013734..92dcc7e64630 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -703,6 +703,34 @@ static int usbhsh_queue_push(struct usb_hcd *hcd, return 0; } +static void usbhsh_queue_force_pop(struct usbhs_priv *priv, + struct usbhs_pipe *pipe) +{ + struct usbhs_pkt *pkt; + + while (1) { + pkt = usbhs_pkt_pop(pipe, NULL); + if (!pkt) + break; + + /* + * if all packet are gone, usbhsh_endpoint_disable() + * will be called. + * then, attached device/endpoint/pipe will be detached + */ + usbhsh_queue_done(priv, pkt); + } +} + +static void usbhsh_queue_force_pop_all(struct usbhs_priv *priv) +{ + struct usbhs_pipe *pos; + int i; + + usbhs_for_each_pipe_with_dcp(pos, priv, i) + usbhsh_queue_force_pop(priv, pos); +} + /* * DCP setup stage */ @@ -1106,6 +1134,8 @@ static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv, USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_LOW_SPEED); + usbhsh_queue_force_pop_all(priv); + usbhs_bus_send_reset(priv); msleep(20); usbhs_bus_send_sof_enable(priv); @@ -1309,6 +1339,12 @@ static int usbhsh_irq_dtch(struct usbhs_priv *priv, hpriv->mod.irq_attch = usbhsh_irq_attch; usbhs_irq_callback_update(priv, &hpriv->mod); + /* + * usbhsh_queue_force_pop_all() should be called + * after usbhsh_is_running() becomes invalid. + */ + usbhsh_queue_force_pop_all(priv); + return 0; } From 15a3838b101b292c2e40824d843a4d8871ac4010 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Dec 2011 18:31:53 -0800 Subject: [PATCH 50/50] usb: renesas_usbhs: show error reason on usbhsh_urb_enqueu() Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 92dcc7e64630..aa50eaaffcb6 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -949,12 +949,15 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, if (!usbhsh_is_running(hpriv)) { ret = -EIO; + dev_err(dev, "host is not running\n"); goto usbhsh_urb_enqueue_error_not_linked; } ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) + if (ret) { + dev_err(dev, "urb link failed\n"); goto usbhsh_urb_enqueue_error_not_linked; + } /* * attach udev if needed @@ -964,6 +967,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, new_udev = usbhsh_device_attach(hpriv, urb); if (!new_udev) { ret = -EIO; + dev_err(dev, "device attach failed\n"); goto usbhsh_urb_enqueue_error_not_linked; } } @@ -974,8 +978,10 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, */ if (!usbhsh_ep_to_uep(ep)) { ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); - if (ret < 0) + if (ret < 0) { + dev_err(dev, "endpoint attach failed\n"); goto usbhsh_urb_enqueue_error_free_device; + } } /* @@ -989,8 +995,10 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, else break; } - if (ret < 0) + if (ret < 0) { + dev_err(dev, "pipe attach failed\n"); goto usbhsh_urb_enqueue_error_free_endpoint; + } /* * push packet