Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[pandora-kernel.git] / drivers / usb / renesas_usbhs / mod_host.c
index 7955de5..1834cf5 100644 (file)
  *
  * +--------+                                  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,38 +154,13 @@ 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)
-{
-       INIT_LIST_HEAD(&hpriv->ureq_link_active);
-       INIT_LIST_HEAD(&hpriv->ureq_link_free);
-}
-
-static void usbhsh_req_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_req_alloc(struct usbhsh_hpriv *hpriv,
+static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv,
                                               struct urb *urb,
                                               gfp_t mem_flags)
 {
@@ -209,270 +168,460 @@ static struct usbhsh_request *usbhsh_req_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;
 
        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;
+       usbhsh_urb_to_ureq(ureq->urb) = NULL;
+       ureq->urb = NULL;
 
-       usbhs_pkt_init(pkt);
+       kfree(ureq);
+}
 
+/*
+ *             status
+ */
+static int usbhsh_is_running(struct usbhsh_hpriv *hpriv)
+{
        /*
-        * removed from "active" list,
-        * and push it to "free" list
+        * we can decide some device is attached or not
+        * by checking mod.irq_attch
+        * see
+        *      usbhsh_irq_attch()
+        *      usbhsh_irq_dtch()
         */
-       ureq->urb = NULL;
-       list_del_init(&ureq->ureq_link);
-       list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free);
+       return (hpriv->mod.irq_attch == NULL);
 }
 
 /*
- *             device control
+ *             pipe control
  */
-
-static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
+static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv,
+                                         struct urb *urb,
+                                         struct usbhs_pkt *pkt)
 {
-       return !list_empty(&udev->ep_list_head);
-}
+       int len = urb->actual_length;
+       int maxp = usb_endpoint_maxp(&urb->ep->desc);
+       int t = 0;
 
-static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv,
-                                                struct urb *urb)
-{
-       struct usbhsh_device *udev = NULL;
-       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);
-       int i;
+       /* DCP is out of sequence control */
+       if (usb_pipecontrol(urb->pipe))
+               return;
 
        /*
-        * device 0
+        * 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]
         */
-       if (0 == usb_pipedevice(urb->pipe)) {
-               udev = usbhsh_device0(hpriv);
-               goto usbhsh_device_find;
-       }
 
        /*
-        * find unused device
+        * next sequence depends on actual_length
+        *
+        * ex) actual_length = 1147, maxp = 512
+        * data0 : 512
+        * data1 : 512
+        * data0 : 123
+        * data1 is the next sequence
         */
-       usbhsh_for_each_udev(udev, hpriv, i) {
-               if (usbhsh_udev_to_usbv(udev))
-                       continue;
-               goto usbhsh_device_find;
+       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 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;
        }
 
-       dev_err(dev, "no free usbhsh_device\n");
+       usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
 
-       return NULL;
+               /* check pipe type */
+               if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc)))
+                       continue;
 
-usbhsh_device_find:
-       if (usbhsh_device_has_endpoint(udev))
-               dev_warn(dev, "udev have old endpoint\n");
+               /* 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;
+               }
 
-       /* uep will be attached */
-       INIT_LIST_HEAD(&udev->ep_list_head);
+               /* check pipe is free */
+               if (usbhsh_pipe_to_uep(pipe))
+                       continue;
 
-       /*
-        * usbhsh_usbv_to_udev()
-        * usbhsh_udev_to_usbv()
-        * will be enable
-        */
-       dev_set_drvdata(&usbv->dev, udev);
-       udev->usbv = usbv;
+               /*
+                * 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;
 
-       /* set device config */
-       usbhs_set_device_speed(priv,
-                              usbhsh_device_number(hpriv, udev),
-                              usbhsh_device_number(hpriv, udev),
-                              0, /* FIXME no parent */
-                              usbv->speed);
+               usbhs_pipe_config_update(pipe,
+                                        usbhsh_device_number(hpriv, udev),
+                                        usb_endpoint_num(desc),
+                                        usb_endpoint_maxp(desc));
 
-       dev_dbg(dev, "%s [%d](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev), udev);
+               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");
 
-       return udev;
+               ret = 0;
+               break;
+       }
+
+usbhsh_pipe_attach_done:
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
+
+       return ret;
 }
 
-static void usbhsh_device_free(struct usbhsh_hpriv *hpriv,
-                              struct usbhsh_device *udev)
+static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
+                              struct usbhsh_ep *uep)
 {
-       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
-       struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+       struct usbhs_pipe *pipe;
+       struct device *dev = usbhs_priv_to_dev(priv);
+       unsigned long flags;
 
-       dev_dbg(dev, "%s [%d](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev), udev);
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
 
-       if (usbhsh_device_has_endpoint(udev))
-               dev_warn(dev, "udev still have endpoint\n");
+       pipe = usbhsh_uep_to_pipe(uep);
 
-       /*
-        * usbhsh_usbv_to_udev()
-        * usbhsh_udev_to_usbv()
-        * will be disable
-        */
-       dev_set_drvdata(&usbv->dev, NULL);
-       udev->usbv = NULL;
+       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 ******************/
 }
 
 /*
- *             end-point control
+ *             endpoint 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)
+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_hcd *hcd = usbhsh_hpriv_to_hcd(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 *pipe, *best_pipe;
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct device *dev = usbhs_priv_to_dev(priv);
        struct usb_endpoint_descriptor *desc = &ep->desc;
-       int type, i, dir_in;
-       unsigned int min_usr;
-
-       dir_in_req = !!dir_in_req;
+       unsigned long flags;
 
        uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags);
        if (!uep) {
                dev_err(dev, "usbhsh_ep alloc fail\n");
-               return NULL;
+               return -ENOMEM;
        }
 
-       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);
+
+       /*
+        * init endpoint
+        */
+       INIT_LIST_HEAD(&uep->ep_list);
+       list_add_tail(&uep->ep_list, &udev->ep_list_head);
+
+       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_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);
+       unsigned long flags;
+
+       if (!uep)
+               return;
+
+       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_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;
+
+       /*
+        * 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 best pipe for endpoint
-        * see
-        *      HARDWARE LIMITATION
+        * find unused device
         */
-       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))
+       usbhsh_for_each_udev(pos, hpriv, i) {
+               if (usbhsh_udev_is_used(pos))
                        continue;
+               udev = pos;
+               break;
+       }
 
-               dir_in = !!usbhs_pipe_is_dir_in(pipe);
-               if (0 != (dir_in - dir_in_req))
-                       continue;
+       if (udev) {
+               /*
+                * usbhsh_usbv_to_udev()
+                * usbhsh_udev_to_usbv()
+                * will be enable
+                */
+               dev_set_drvdata(&usbv->dev, udev);
+               udev->usbv = usbv;
+       }
 
-               info = usbhsh_pipe_info(pipe);
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
 
-               if (min_usr > info->usr_cnt) {
-                       min_usr         = info->usr_cnt;
-                       best_pipe       = pipe;
-               }
+       if (!udev) {
+               dev_err(dev, "no free usbhsh_device\n");
+               return NULL;
        }
 
-       if (unlikely(!best_pipe)) {
-               dev_err(dev, "couldn't find best pipe\n");
-               kfree(uep);
-               return NULL;
+       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);
        }
-usbhsh_endpoint_alloc_find_pipe:
+
+       /* uep will be attached */
+       INIT_LIST_HEAD(&udev0->ep_list_head);
+       INIT_LIST_HEAD(&udev->ep_list_head);
+
        /*
-        * init uep
+        * set device0 config
         */
-       uep->pipe       = best_pipe;
-       uep->maxp       = usb_endpoint_maxp(desc);
-       usbhsh_uep_to_udev(uep) = udev;
-       usbhsh_ep_to_uep(ep)    = uep;
+       usbhs_set_device_config(priv,
+                               0, 0, 0, usbv->speed);
 
        /*
-        * update pipe user count
+        * set new device config
         */
-       info = usbhsh_pipe_info(best_pipe);
-       info->usr_cnt++;
+       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);
 
-       /* init this endpoint, and attach it to udev */
-       INIT_LIST_HEAD(&uep->ep_list);
-       list_add_tail(&uep->ep_list, &udev->ep_list_head);
+               upphub  = usbhsh_device_number(hpriv, parent);
+               hubport = usbhsh_device_hubport(udev);
 
-       /*
-        * usbhs_pipe_config_update() should be called after
-        * usbhs_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 connecte to Hub [%d:%d](%p)\n", __func__,
+                       upphub, hubport, parent);
+       }
 
-       dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev),
-               usbhs_pipe_name(uep->pipe), uep);
+       usbhs_set_device_config(priv,
+                              usbhsh_device_number(hpriv, udev),
+                              upphub, hubport, usbv->speed);
 
-       return uep;
+       dev_dbg(dev, "%s [%d](%p)\n", __func__,
+               usbhsh_device_number(hpriv, udev), udev);
+
+       return udev;
 }
 
-void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,
-                         struct usb_host_endpoint *ep)
+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 = usbhs_priv_to_dev(priv);
-       struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
-       struct usbhsh_pipe_info *info;
+       struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+       unsigned long flags;
 
-       if (!uep)
-               return;
+       dev_dbg(dev, "%s [%d](%p)\n", __func__,
+               usbhsh_device_number(hpriv, udev), udev);
 
-       dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-               usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
-               usbhs_pipe_name(uep->pipe), uep);
+       if (usbhsh_device_has_endpoint(udev)) {
+               dev_warn(dev, "udev still have endpoint\n");
+               usbhsh_endpoint_detach_all(hpriv, udev);
+       }
 
-       info = usbhsh_pipe_info(uep->pipe);
-       info->usr_cnt--;
+       /*
+        * There is nothing to do if it is device0.
+        * see
+        *  usbhsh_device_attach()
+        *  usbhsh_device_get()
+        */
+       if (0 == usbhsh_device_number(hpriv, udev))
+               return;
 
-       /* remove this endpoint from udev */
-       list_del_init(&uep->ep_list);
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
 
-       usbhsh_uep_to_udev(uep) = NULL;
-       usbhsh_ep_to_uep(ep) = NULL;
+       /*
+        * usbhsh_usbv_to_udev()
+        * usbhsh_udev_to_usbv()
+        * will be disable
+        */
+       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;