diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 12:09:47 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-09 12:09:47 -0800 | 
| commit | 55b81e6f2795484ea8edf5805c95c007cacfa736 (patch) | |
| tree | c3724975107857fcc03b5dd649c462e4f72397be /drivers/usb/renesas_usbhs/mod_host.c | |
| parent | 5983faf942f260023e547f3c5f38c1033c35cc9b (diff) | |
| parent | 08e87d0d773dc9ca5faf4c3306e238ed0ea129b0 (diff) | |
| download | olio-linux-3.10-55b81e6f2795484ea8edf5805c95c007cacfa736.tar.xz olio-linux-3.10-55b81e6f2795484ea8edf5805c95c007cacfa736.zip  | |
Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
  USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
  xhci: Clean up 32-bit build warnings.
  USB: update documentation for usbmon
  usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
  drivers/usb/class/cdc-acm.c: clear dangling pointer
  drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
  drivers/usb/host/isp1760-if.c: introduce missing kfree
  usb: option: add ZD Incorporated HSPA modem
  usb: ch9: fix up MaxStreams helper
  USB: usb-skeleton.c: cleanup open_count
  USB: usb-skeleton.c: fix open/disconnect race
  xhci: Properly handle COMP_2ND_BW_ERR
  USB: remove dead code from suspend/resume path
  USB: add quirk for another camera
  drivers: usb: wusbcore: Fix dependency for USB_WUSB
  xhci: Better debugging for critical host errors.
  xhci: Be less verbose during URB cancellation.
  xhci: Remove debugging about ring structure allocation.
  xhci: Remove debugging about toggling cycle bits.
  xhci: Remove debugging for individual transfers.
  ...
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod_host.c')
| -rw-r--r-- | drivers/usb/renesas_usbhs/mod_host.c | 950 | 
1 files changed, 591 insertions, 359 deletions
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 7955de58995..1834cf50888 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -45,36 +45,34 @@   *   * +--------+					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; -	struct list_head	ureq_link; /* see hpriv :: ureq_link_xxx */  };  struct usbhsh_device { @@ -83,11 +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,16 +95,9 @@ 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; - -	/* see usbhsh_req_alloc/free */ -	struct list_head	ureq_link_active; -	struct list_head	ureq_link_free;  }; @@ -119,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;			\ @@ -152,15 +131,20 @@ 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)  #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) +#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)  #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) @@ -170,156 +154,428 @@ 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 struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, +					       struct urb *urb, +					       gfp_t mem_flags)  { -	INIT_LIST_HEAD(&hpriv->ureq_link_active); -	INIT_LIST_HEAD(&hpriv->ureq_link_free); +	struct usbhsh_request *ureq; +	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	struct device *dev = usbhs_priv_to_dev(priv); + +	ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); +	if (!ureq) { +		dev_err(dev, "ureq alloc fail\n"); +		return NULL; +	} + +	usbhs_pkt_init(&ureq->pkt); +	ureq->urb = urb; +	usbhsh_urb_to_ureq(urb) = ureq; + +	return ureq;  } -static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) +static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, +			    struct usbhsh_request *ureq)  { -	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); -	struct device *dev = usbhsh_hcd_to_dev(hcd); -	struct usbhsh_request *ureq, *next; +	usbhsh_urb_to_ureq(ureq->urb) = NULL; +	ureq->urb = NULL; -	/* 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(ureq); +} -	/* kfree all free ureq */ -	list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link) -		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);  } -static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, -					       struct urb *urb, -					       gfp_t mem_flags) +/* + *		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); + +static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, +			      struct urb *urb)  { -	struct usbhsh_request *ureq;  	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; -	if (list_empty(&hpriv->ureq_link_free)) {  		/* -		 * create new one if there is no free ureq +		 * attach pipe to uep +		 * +		 * usbhs_pipe_config_update() should be called after +		 * usbhs_set_device_config() +		 * see +		 *  DCPMAXP/PIPEMAXP  		 */ -		ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); -		if (ureq) -			INIT_LIST_HEAD(&ureq->ureq_link); +		usbhsh_uep_to_pipe(uep)		= pipe; +		usbhsh_pipe_to_uep(pipe)	= uep; + +		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 { -		/* -		 * 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); +		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));  	} -	if (!ureq) { -		dev_err(dev, "ureq alloc fail\n"); -		return NULL; +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ +} + +/* + *		endpoint 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 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;  	} -	usbhs_pkt_init(&ureq->pkt); +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags);  	/* -	 * push it to "active" list +	 * init endpoint  	 */ -	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); -	ureq->urb = urb; +	INIT_LIST_HEAD(&uep->ep_list); +	list_add_tail(&uep->ep_list, &udev->ep_list_head); -	return ureq; +	usbhsh_uep_to_udev(uep)	= udev; +	usbhsh_uep_to_ep(uep)	= ep; +	usbhsh_ep_to_uep(ep)	= uep; + +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/ + +	dev_dbg(dev, "%s [%d-%d]\n", __func__, +		usbhsh_device_number(hpriv, udev), +		usb_endpoint_num(desc)); + +	return 0;  } -static void usbhsh_req_free(struct usbhsh_hpriv *hpriv, -			    struct usbhsh_request *ureq) +static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, +				   struct usb_host_endpoint *ep)  { -	struct usbhs_pkt *pkt = &ureq->pkt; +	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); +	unsigned long flags; -	usbhs_pkt_init(pkt); +	if (!uep) +		return; -	/* -	 * removed from "active" list, -	 * and push it to "free" list -	 */ -	ureq->urb = NULL; -	list_del_init(&ureq->ureq_link); -	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); +	dev_dbg(dev, "%s [%d-%d]\n", __func__, +		usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), +		usb_endpoint_num(&ep->desc)); + +	if (usbhsh_uep_to_pipe(uep)) +		usbhsh_pipe_detach(hpriv, uep); + +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags); + +	/* remove this endpoint from udev */ +	list_del_init(&uep->ep_list); + +	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   */ +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)  {  	return !list_empty(&udev->ep_list_head);  } -static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, +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);  	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); +	unsigned long flags; +	u16 upphub, hubport;  	int i;  	/* -	 * device 0 +	 * 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)) { -		udev = usbhsh_device0(hpriv); -		goto usbhsh_device_find; +	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 unused device  	 */ -	usbhsh_for_each_udev(udev, hpriv, i) { -		if (usbhsh_udev_to_usbv(udev)) +	usbhsh_for_each_udev(pos, hpriv, i) { +		if (usbhsh_udev_is_used(pos))  			continue; -		goto usbhsh_device_find; +		udev = pos; +		break;  	} -	dev_err(dev, "no free usbhsh_device\n"); +	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 ******************/ -	return NULL; +	if (!udev) { +		dev_err(dev, "no free usbhsh_device\n"); +		return NULL; +	} -usbhsh_device_find: -	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)) { +		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);  	INIT_LIST_HEAD(&udev->ep_list_head);  	/* -	 * usbhsh_usbv_to_udev() -	 * usbhsh_udev_to_usbv() -	 * will be enable +	 * set device0 config  	 */ -	dev_set_drvdata(&usbv->dev, udev); -	udev->usbv = usbv; +	usbhs_set_device_config(priv, +				0, 0, 0, usbv->speed); -	/* set device config */ -	usbhs_set_device_speed(priv, -			       usbhsh_device_number(hpriv, udev), +	/* +	 * set new device config +	 */ +	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); +	} + +	usbhs_set_device_config(priv,  			       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); @@ -327,152 +583,45 @@ usbhsh_device_find:  	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); +	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); -	if (usbhsh_device_has_endpoint(udev)) +	if (usbhsh_device_has_endpoint(udev)) {  		dev_warn(dev, "udev still have endpoint\n"); - -	/* -	 * usbhsh_usbv_to_udev() -	 * usbhsh_udev_to_usbv() -	 * will be disable -	 */ -	dev_set_drvdata(&usbv->dev, NULL); -	udev->usbv = NULL; -} - -/* - *		end-point control - */ -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 usb_endpoint_descriptor *desc = &ep->desc; -	int type, i, dir_in; -	unsigned int min_usr; - -	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; +		usbhsh_endpoint_detach_all(hpriv, udev);  	}  	/* -	 * find best pipe for endpoint +	 * There is nothing to do if it is device0.  	 * see -	 *	HARDWARE LIMITATION +	 *  usbhsh_device_attach() +	 *  usbhsh_device_get()  	 */ -	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; - -		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 (unlikely(!best_pipe)) { -		dev_err(dev, "couldn't find best pipe\n"); -		kfree(uep); -		return NULL; -	} -usbhsh_endpoint_alloc_find_pipe: -	/* -	 * init uep -	 */ -	uep->pipe	= best_pipe; -	uep->maxp	= usb_endpoint_maxp(desc); -	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++; +	if (0 == usbhsh_device_number(hpriv, udev)) +		return; -	/* init this endpoint, and attach it to udev */ -	INIT_LIST_HEAD(&uep->ep_list); -	list_add_tail(&uep->ep_list, &udev->ep_list_head); +	/********************  spin lock ********************/ +	usbhs_lock(priv, flags);  	/* -	 * usbhs_pipe_config_update() should be called after -	 * usbhs_device_config() -	 * see -	 *  DCPMAXP/PIPEMAXP +	 * usbhsh_usbv_to_udev() +	 * usbhsh_udev_to_usbv() +	 * will be disable  	 */ -	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 uep; -} - -void usbhsh_endpoint_free(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; - -	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); - -	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; +	dev_set_drvdata(&usbv->dev, NULL); +	udev->usbv = NULL; -	kfree(uep); +	usbhs_unlock(priv, flags); +	/********************  spin unlock ******************/  }  /* @@ -480,11 +629,12 @@ 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;  	struct device *dev = usbhs_priv_to_dev(priv); +	int status = 0;  	dev_dbg(dev, "%s\n", __func__); @@ -493,29 +643,43 @@ 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_req_free(hpriv, ureq); -	usbhsh_urb_to_ureq(urb) = NULL; +	usbhsh_ureq_free(hpriv, ureq); + +	usbhsh_endpoint_sequence_save(hpriv, urb, pkt); +	usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));  	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, -			     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 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; -	int len; +	int len, sequence;  	if (usb_pipeisoc(urb->pipe)) {  		dev_err(dev, "pipe iso is not supported now\n");  		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; +	} +  	if (usb_pipein(urb->pipe))  		pipe->handler = &usbhs_fifo_pio_pop_handler;  	else @@ -524,25 +688,59 @@ 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, pkt, usbhsh_queue_done, -		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); +	usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, +		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET), +		       sequence); +  	usbhs_pkt_start(pipe);  	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   */  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; @@ -570,11 +768,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);  	} @@ -595,82 +797,80 @@ 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_urb_to_ureq(urb) = NULL; +	usbhsh_ureq_free(hpriv, ureq);  } -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;  	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)); +		       (urb->transfer_flags & URB_ZERO_PACKET), +		       -1); + +	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_req_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;  	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); +		       0, -1); + +	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 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;  	dev_dbg(dev, "%s\n", __func__); @@ -686,13 +886,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 @@ -729,71 +938,82 @@ 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_request *ureq; -	struct usbhsh_device *udev, *new_udev = NULL; -	struct usbhs_pipe *pipe; -	struct usbhsh_ep *uep; +	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"); +	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; +	}  	/* -	 * get udev +	 * attach udev if needed +	 * see [image of mod_host]  	 */ -	udev = usbhsh_usbv_to_udev(usbv); -	if (!udev) { -		new_udev = usbhsh_device_alloc(hpriv, urb); -		if (!new_udev) +	if (!usbhsh_device_get(hpriv, urb)) { +		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; - -		udev = new_udev; +		}  	}  	/* -	 * get uep +	 * attach endpoint if needed +	 * see [image of mod_host]  	 */ -	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) { +			dev_err(dev, "endpoint attach failed\n");  			goto usbhsh_urb_enqueue_error_free_device; +		}  	} -	pipe = usbhsh_uep_to_pipe(uep);  	/* -	 * alloc new request +	 * attach pipe to endpoint +	 * see [image of mod_host]  	 */ -	ureq = usbhsh_req_alloc(hpriv, urb, mem_flags); -	if (unlikely(!ureq)) { -		ret = -ENOMEM; +	for (i = 0; i < 1024; i++) { +		ret = usbhsh_pipe_attach(hpriv, urb); +		if (ret < 0) +			msleep(100); +		else +			break; +	} +	if (ret < 0) { +		dev_err(dev, "pipe attach failed\n");  		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, urb, mem_flags);  	else -		usbhsh_queue_push(hcd, pipe, urb); +		ret = usbhsh_queue_push(hcd, urb, mem_flags); -	return 0; +	return ret;  usbhsh_urb_enqueue_error_free_endpoint: -	usbhsh_endpoint_free(hpriv, ep); +	usbhsh_endpoint_detach(hpriv, ep);  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__); @@ -807,8 +1027,11 @@ 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_urb_to_ureq(urb) = NULL; +		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; @@ -823,7 +1046,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,15 +1054,14 @@ 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); -	ep->hcpriv = NULL; +	usbhsh_endpoint_detach(hpriv, ep);  	/*  	 * if there is no endpoint,  	 * 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) @@ -919,6 +1141,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); @@ -1082,6 +1306,20 @@ 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. +	 * +	 * 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); +  	return 0;  } @@ -1096,6 +1334,24 @@ 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 +	 * +	 * 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); + +	/* +	 * usbhsh_queue_force_pop_all() should be called +	 * after usbhsh_is_running() becomes invalid. +	 */ +	usbhsh_queue_force_pop_all(priv); +  	return 0;  } @@ -1131,7 +1387,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); @@ -1140,7 +1395,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, @@ -1174,7 +1428,7 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)  						 dir_in);  		} -		pipe->mod_private = pipe_info + i; +		pipe->mod_private = NULL;  	}  } @@ -1205,9 +1459,7 @@ 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);  	/*  	 * enable irq callback @@ -1242,9 +1494,7 @@ 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);  	dev_dbg(dev, "quit host\n"); @@ -1255,10 +1505,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 */ @@ -1269,12 +1517,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)  	}  	hcd->has_tt = 1; /* for low/full speed */ -	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  	 * @@ -1294,9 +1536,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_req_list_init(hpriv);  	usbhsh_port_stat_init(hpriv);  	/* init all device */ @@ -1308,11 +1547,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) @@ -1320,8 +1554,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_req_list_quit(hpriv); -  	usb_put_hcd(hcd);  	return 0;  |