summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c97
1 files changed, 69 insertions, 28 deletions
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 0dbbc6613c1f..164f28ee9610 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -220,10 +220,30 @@ static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
return !list_empty(&udev->ep_list_head);
}
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+ struct urb *urb)
+{
+ struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+ struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+ /* usbhsh_device_attach() is still not called */
+ if (!udev)
+ return NULL;
+
+ /* if it is device0, return it */
+ if (0 == usb_pipedevice(urb->pipe))
+ return usbhsh_device0(hpriv);
+
+ /* return attached device */
+ return udev;
+}
+
static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
struct urb *urb)
{
struct usbhsh_device *udev = NULL;
+ struct usbhsh_device *udev0 = usbhsh_device0(hpriv);
+ struct usbhsh_device *pos;
struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
struct device *dev = usbhsh_hcd_to_dev(hcd);
struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
@@ -232,31 +252,29 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
u16 upphub, hubport;
int i;
+ /*
+ * This function should be called only while urb is pointing to device0.
+ * It will attach unused usbhsh_device to urb (usbv),
+ * and initialize device0.
+ * You can use usbhsh_device_get() to get "current" udev,
+ * and usbhsh_usbv_to_udev() is for "attached" udev.
+ */
+ if (0 != usb_pipedevice(urb->pipe)) {
+ dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__);
+ return NULL;
+ }
+
/******************** spin lock ********************/
usbhs_lock(priv, flags);
/*
- * find device
+ * find unused device
*/
- if (0 == usb_pipedevice(urb->pipe)) {
- /*
- * device0 is special case
- */
- udev = usbhsh_device0(hpriv);
- if (usbhsh_udev_is_used(udev))
- udev = NULL;
- } else {
- struct usbhsh_device *pos;
-
- /*
- * find unused device
- */
- usbhsh_for_each_udev(pos, hpriv, i) {
- if (usbhsh_udev_is_used(pos))
- continue;
- udev = pos;
- break;
- }
+ usbhsh_for_each_udev(pos, hpriv, i) {
+ if (usbhsh_udev_is_used(pos))
+ continue;
+ udev = pos;
+ break;
}
if (udev) {
@@ -280,9 +298,22 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
if (usbhsh_device_has_endpoint(udev))
dev_warn(dev, "udev have old endpoint\n");
+ if (usbhsh_device_has_endpoint(udev0))
+ dev_warn(dev, "udev0 have old endpoint\n");
+
/* uep will be attached */
+ INIT_LIST_HEAD(&udev0->ep_list_head);
INIT_LIST_HEAD(&udev->ep_list_head);
+ /*
+ * set device0 config
+ */
+ usbhs_set_device_config(priv,
+ 0, 0, 0, usbv->speed);
+
+ /*
+ * set new device config
+ */
upphub = 0;
hubport = 0;
if (!usbhsh_connected_to_rhdev(hcd, udev)) {
@@ -296,7 +327,6 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
upphub, hubport, parent);
}
- /* set device config */
usbhs_set_device_config(priv,
usbhsh_device_number(hpriv, udev),
upphub, hubport, usbv->speed);
@@ -322,6 +352,15 @@ static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv,
if (usbhsh_device_has_endpoint(udev))
dev_warn(dev, "udev still have endpoint\n");
+ /*
+ * There is nothing to do if it is device0.
+ * see
+ * usbhsh_device_attach()
+ * usbhsh_device_get()
+ */
+ if (0 == usbhsh_device_number(hpriv, udev))
+ return;
+
/******************** spin lock ********************/
usbhs_lock(priv, flags);
@@ -345,8 +384,7 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv,
gfp_t mem_flags)
{
struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
- struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
- struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+ struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
struct usb_host_endpoint *ep = urb->ep;
struct usbhsh_ep *uep;
struct usbhsh_pipe_info *info;
@@ -577,11 +615,15 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,
/*
* renesas_usbhs can not use original usb address.
* see HARDWARE LIMITATION.
- * modify usb address here.
+ * modify usb address here to use attached device.
+ * see usbhsh_device_attach()
*/
if (usbhsh_is_request_address(urb)) {
- /* FIXME */
- req.wValue = 1;
+ struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+ struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+ /* udev is a attached device */
+ req.wValue = usbhsh_device_number(hpriv, udev);
dev_dbg(dev, "create new address - %d\n", req.wValue);
}
@@ -742,7 +784,6 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
struct device *dev = usbhs_priv_to_dev(priv);
- struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
struct usb_host_endpoint *ep = urb->ep;
struct usbhsh_device *new_udev = NULL;
int is_dir_in = usb_pipein(urb->pipe);
@@ -758,7 +799,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
/*
* attach udev if needed
*/
- if (!usbhsh_usbv_to_udev(usbv)) {
+ if (!usbhsh_device_get(hpriv, urb)) {
new_udev = usbhsh_device_attach(hpriv, urb);
if (!new_udev) {
ret = -EIO;