usb: renesas_usbhs: modify device attach method
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Fri, 9 Dec 2011 02:27:21 +0000 (18:27 -0800)
committerFelipe Balbi <balbi@ti.com>
Tue, 13 Dec 2011 11:06:23 +0000 (13:06 +0200)
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 <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/renesas_usbhs/mod_host.c

index 0dbbc6613c1ff3b7664265c75c0322a41548be5f..164f28ee9610e8c053c900d114223a14e0b34f75 100644 (file)
@@ -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;