Commit cdfcbd2c authored by Tatyana Brokhman's avatar Tatyana Brokhman Committed by Greg Kroah-Hartman

usb: gadget: dummy_hcd: use the shared_hcd infrastructure

This patch is a preparation for adding SuperSpeed
support to dummy hcd.

It takes the master side fields out of the struct
dummy to a separate structure. The init process
was also modified to resemble the way it is
done by xHCI.
Signed-off-by: default avatarTatyana Brokhman <tlinder@codeaurora.org>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bdb64d72
...@@ -152,6 +152,22 @@ enum dummy_rh_state { ...@@ -152,6 +152,22 @@ enum dummy_rh_state {
DUMMY_RH_RUNNING DUMMY_RH_RUNNING
}; };
struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct timer_list timer;
u32 port_status;
u32 old_status;
unsigned long re_timeout;
struct usb_device *udev;
struct list_head urbp_list;
unsigned active:1;
unsigned old_active:1;
unsigned resuming:1;
};
struct dummy { struct dummy {
spinlock_t lock; spinlock_t lock;
...@@ -167,36 +183,26 @@ struct dummy { ...@@ -167,36 +183,26 @@ struct dummy {
u16 devstatus; u16 devstatus;
unsigned udc_suspended:1; unsigned udc_suspended:1;
unsigned pullup:1; unsigned pullup:1;
unsigned active:1;
unsigned old_active:1;
/* /*
* MASTER/HOST side support * MASTER/HOST side support
*/ */
enum dummy_rh_state rh_state; struct dummy_hcd *hs_hcd;
struct timer_list timer;
u32 port_status;
u32 old_status;
unsigned resuming:1;
unsigned long re_timeout;
struct usb_device *udev;
struct list_head urbp_list;
}; };
static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd) static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
{ {
return (struct dummy *) (hcd->hcd_priv); return (struct dummy_hcd *) (hcd->hcd_priv);
} }
static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum) static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
{ {
return container_of((void *) dum, struct usb_hcd, hcd_priv); return container_of((void *) dum, struct usb_hcd, hcd_priv);
} }
static inline struct device *dummy_dev (struct dummy *dum) static inline struct device *dummy_dev(struct dummy_hcd *dum)
{ {
return dummy_to_hcd(dum)->self.controller; return dummy_hcd_to_hcd(dum)->self.controller;
} }
static inline struct device *udc_dev (struct dummy *dum) static inline struct device *udc_dev (struct dummy *dum)
...@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) ...@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
return container_of (ep->gadget, struct dummy, gadget); return container_of (ep->gadget, struct dummy, gadget);
} }
static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget) static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
{ {
return container_of (gadget, struct dummy, gadget); struct dummy *dum = container_of(gadget, struct dummy, gadget);
return dum->hs_hcd;
} }
static inline struct dummy *gadget_dev_to_dummy (struct device *dev) static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
...@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev) ...@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
return container_of (dev, struct dummy, gadget.dev); return container_of (dev, struct dummy, gadget.dev);
} }
static struct dummy *the_controller; static struct dummy the_controller;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -260,60 +267,64 @@ stop_activity (struct dummy *dum) ...@@ -260,60 +267,64 @@ stop_activity (struct dummy *dum)
} }
/* caller must hold lock */ /* caller must hold lock */
static void static void set_link_state(struct dummy_hcd *dum_hcd)
set_link_state (struct dummy *dum)
{ {
dum->active = 0; struct dummy *dum = dum_hcd->dum;
if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
dum->port_status = 0; dum_hcd->active = 0;
if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0)
dum_hcd->port_status = 0;
/* UDC suspend must cause a disconnect */ /* UDC suspend must cause a disconnect */
else if (!dum->pullup || dum->udc_suspended) { else if (!dum->pullup || dum->udc_suspended) {
dum->port_status &= ~(USB_PORT_STAT_CONNECTION | dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
USB_PORT_STAT_ENABLE | USB_PORT_STAT_ENABLE |
USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_LOW_SPEED |
USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_HIGH_SPEED |
USB_PORT_STAT_SUSPEND); USB_PORT_STAT_SUSPEND);
if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); dum_hcd->port_status |=
(USB_PORT_STAT_C_CONNECTION << 16);
} else { } else {
dum->port_status |= USB_PORT_STAT_CONNECTION; dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); dum_hcd->port_status |=
if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) (USB_PORT_STAT_C_CONNECTION << 16);
dum->port_status &= ~USB_PORT_STAT_SUSPEND; if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
dum->rh_state != DUMMY_RH_SUSPENDED) else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum->active = 1; dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
} dum_hcd->active = 1;
}
if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
dum->resuming = 0; if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
dum_hcd->active)
if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || dum_hcd->resuming = 0;
(dum->port_status & USB_PORT_STAT_RESET) != 0) {
if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
(dum->old_status & USB_PORT_STAT_RESET) == 0 && (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
(dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
dum->driver) { dum->driver) {
stop_activity (dum); stop_activity (dum);
spin_unlock (&dum->lock); spin_unlock (&dum->lock);
dum->driver->disconnect (&dum->gadget); dum->driver->disconnect (&dum->gadget);
spin_lock (&dum->lock); spin_lock (&dum->lock);
} }
} else if (dum->active != dum->old_active) { } else if (dum_hcd->active != dum_hcd->old_active) {
if (dum->old_active && dum->driver->suspend) { if (dum_hcd->old_active && dum->driver->suspend) {
spin_unlock (&dum->lock); spin_unlock (&dum->lock);
dum->driver->suspend (&dum->gadget); dum->driver->suspend (&dum->gadget);
spin_lock (&dum->lock); spin_lock (&dum->lock);
} else if (!dum->old_active && dum->driver->resume) { } else if (!dum_hcd->old_active && dum->driver->resume) {
spin_unlock (&dum->lock); spin_unlock (&dum->lock);
dum->driver->resume (&dum->gadget); dum->driver->resume (&dum->gadget);
spin_lock (&dum->lock); spin_lock (&dum->lock);
} }
} }
dum->old_status = dum->port_status; dum_hcd->old_status = dum_hcd->port_status;
dum->old_active = dum->active; dum_hcd->old_active = dum_hcd->active;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -332,6 +343,7 @@ static int ...@@ -332,6 +343,7 @@ static int
dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{ {
struct dummy *dum; struct dummy *dum;
struct dummy_hcd *dum_hcd;
struct dummy_ep *ep; struct dummy_ep *ep;
unsigned max; unsigned max;
int retval; int retval;
...@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ...@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|| desc->bDescriptorType != USB_DT_ENDPOINT) || desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL; return -EINVAL;
dum = ep_to_dummy (ep); dum = ep_to_dummy (ep);
if (!dum->driver || !is_enabled (dum)) if (!dum->driver)
return -ESHUTDOWN;
dum_hcd = dum->hs_hcd;
if (!is_enabled(dum_hcd))
return -ESHUTDOWN; return -ESHUTDOWN;
max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
/*
* For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
* maximum packet size.
*/
max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
/* drivers must not request bad settings, since lower levels /* drivers must not request bad settings, since lower levels
* (hardware or its drivers) may not check. some endpoints * (hardware or its drivers) may not check. some endpoints
...@@ -515,6 +535,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, ...@@ -515,6 +535,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
struct dummy_ep *ep; struct dummy_ep *ep;
struct dummy_request *req; struct dummy_request *req;
struct dummy *dum; struct dummy *dum;
struct dummy_hcd *dum_hcd;
unsigned long flags; unsigned long flags;
req = usb_request_to_dummy_request (_req); req = usb_request_to_dummy_request (_req);
...@@ -526,7 +547,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, ...@@ -526,7 +547,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
return -EINVAL; return -EINVAL;
dum = ep_to_dummy (ep); dum = ep_to_dummy (ep);
if (!dum->driver || !is_enabled (dum)) dum_hcd = dum->hs_hcd;
if (!dum->driver || !is_enabled(dum_hcd))
return -ESHUTDOWN; return -ESHUTDOWN;
#if 0 #if 0
...@@ -670,24 +692,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget) ...@@ -670,24 +692,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
static int dummy_wakeup (struct usb_gadget *_gadget) static int dummy_wakeup (struct usb_gadget *_gadget)
{ {
struct dummy *dum; struct dummy_hcd *dum_hcd;
dum = gadget_to_dummy (_gadget); dum_hcd = gadget_to_dummy_hcd(_gadget);
if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
| (1 << USB_DEVICE_REMOTE_WAKEUP)))) | (1 << USB_DEVICE_REMOTE_WAKEUP))))
return -EINVAL; return -EINVAL;
if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0) if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
return -ENOLINK; return -ENOLINK;
if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum->rh_state != DUMMY_RH_SUSPENDED) dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
return -EIO; return -EIO;
/* FIXME: What if the root hub is suspended but the port isn't? */ /* FIXME: What if the root hub is suspended but the port isn't? */
/* hub notices our request, issues downstream resume, etc */ /* hub notices our request, issues downstream resume, etc */
dum->resuming = 1; dum_hcd->resuming = 1;
dum->re_timeout = jiffies + msecs_to_jiffies(20); dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
return 0; return 0;
} }
...@@ -695,7 +717,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) ...@@ -695,7 +717,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
{ {
struct dummy *dum; struct dummy *dum;
dum = gadget_to_dummy (_gadget); dum = (gadget_to_dummy_hcd(_gadget))->dum;
if (value) if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else else
...@@ -708,13 +730,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value) ...@@ -708,13 +730,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
struct dummy *dum; struct dummy *dum;
unsigned long flags; unsigned long flags;
dum = gadget_to_dummy (_gadget); dum = gadget_to_dummy_hcd(_gadget)->dum;
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
dum->pullup = (value != 0); dum->pullup = (value != 0);
set_link_state (dum); set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0; return 0;
} }
...@@ -764,7 +785,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); ...@@ -764,7 +785,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
static int dummy_udc_start(struct usb_gadget_driver *driver, static int dummy_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *)) int (*bind)(struct usb_gadget *))
{ {
struct dummy *dum = the_controller; struct dummy *dum = &the_controller;
int retval, i; int retval, i;
if (!dum) if (!dum)
...@@ -800,7 +821,8 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, ...@@ -800,7 +821,8 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
} }
dum->gadget.ep0 = &dum->ep [0].ep; dum->gadget.ep0 = &dum->ep [0].ep;
dum->ep [0].ep.maxpacket = 64; dum->gadget.speed = min((u8)driver->speed, (u8)USB_SPEED_HIGH) ;
dum->ep[0].ep.maxpacket = 64;
list_del_init (&dum->ep [0].ep.ep_list); list_del_init (&dum->ep [0].ep.ep_list);
INIT_LIST_HEAD(&dum->fifo_req.queue); INIT_LIST_HEAD(&dum->fifo_req.queue);
...@@ -819,16 +841,18 @@ static int dummy_udc_start(struct usb_gadget_driver *driver, ...@@ -819,16 +841,18 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
/* khubd will enumerate this in a while */ /* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock); spin_lock_irq (&dum->lock);
dum->pullup = 1; dum->pullup = 1;
set_link_state (dum); dum->gadget.is_otg =
(dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
set_link_state(dum->hs_hcd);
spin_unlock_irq (&dum->lock); spin_unlock_irq (&dum->lock);
usb_hcd_poll_rh_status (dummy_to_hcd (dum)); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0; return 0;
} }
static int dummy_udc_stop(struct usb_gadget_driver *driver) static int dummy_udc_stop(struct usb_gadget_driver *driver)
{ {
struct dummy *dum = the_controller; struct dummy *dum = &the_controller;
unsigned long flags; unsigned long flags;
if (!dum) if (!dum)
...@@ -841,7 +865,7 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) ...@@ -841,7 +865,7 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
dum->pullup = 0; dum->pullup = 0;
set_link_state (dum); set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
driver->unbind (&dum->gadget); driver->unbind (&dum->gadget);
...@@ -850,10 +874,9 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver) ...@@ -850,10 +874,9 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
dum->pullup = 0; dum->pullup = 0;
set_link_state (dum); set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0; return 0;
} }
...@@ -874,25 +897,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode); ...@@ -874,25 +897,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
static void static void
dummy_gadget_release (struct device *dev) dummy_gadget_release (struct device *dev)
{ {
struct dummy *dum = gadget_dev_to_dummy (dev); return;
usb_put_hcd (dummy_to_hcd (dum));
} }
static int dummy_udc_probe (struct platform_device *pdev) static int dummy_udc_probe (struct platform_device *pdev)
{ {
struct dummy *dum = the_controller; struct dummy *dum = &the_controller;
int rc; int rc;
usb_get_hcd(dummy_to_hcd(dum));
dum->gadget.name = gadget_name; dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops; dum->gadget.ops = &dummy_ops;
dum->gadget.is_dualspeed = 1; dum->gadget.is_dualspeed = 1;
/* maybe claim OTG support, though we won't complete HNP */
dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
dev_set_name(&dum->gadget.dev, "gadget"); dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev; dum->gadget.dev.parent = &pdev->dev;
dum->gadget.dev.release = dummy_gadget_release; dum->gadget.dev.release = dummy_gadget_release;
...@@ -937,10 +953,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state) ...@@ -937,10 +953,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
dev_dbg (&pdev->dev, "%s\n", __func__); dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock); spin_lock_irq (&dum->lock);
dum->udc_suspended = 1; dum->udc_suspended = 1;
set_link_state (dum); set_link_state(dum->hs_hcd);
spin_unlock_irq (&dum->lock); spin_unlock_irq (&dum->lock);
usb_hcd_poll_rh_status (dummy_to_hcd (dum)); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0; return 0;
} }
...@@ -951,10 +967,10 @@ static int dummy_udc_resume (struct platform_device *pdev) ...@@ -951,10 +967,10 @@ static int dummy_udc_resume (struct platform_device *pdev)
dev_dbg (&pdev->dev, "%s\n", __func__); dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock); spin_lock_irq (&dum->lock);
dum->udc_suspended = 0; dum->udc_suspended = 0;
set_link_state (dum); set_link_state(dum->hs_hcd);
spin_unlock_irq (&dum->lock); spin_unlock_irq (&dum->lock);
usb_hcd_poll_rh_status (dummy_to_hcd (dum)); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0; return 0;
} }
...@@ -988,7 +1004,7 @@ static int dummy_urb_enqueue ( ...@@ -988,7 +1004,7 @@ static int dummy_urb_enqueue (
struct urb *urb, struct urb *urb,
gfp_t mem_flags gfp_t mem_flags
) { ) {
struct dummy *dum; struct dummy_hcd *dum_hcd;
struct urbp *urbp; struct urbp *urbp;
unsigned long flags; unsigned long flags;
int rc; int rc;
...@@ -1001,51 +1017,51 @@ static int dummy_urb_enqueue ( ...@@ -1001,51 +1017,51 @@ static int dummy_urb_enqueue (
return -ENOMEM; return -ENOMEM;
urbp->urb = urb; urbp->urb = urb;
dum = hcd_to_dummy (hcd); dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave(&dum_hcd->dum->lock, flags);
rc = usb_hcd_link_urb_to_ep(hcd, urb); rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) { if (rc) {
kfree(urbp); kfree(urbp);
goto done; goto done;
} }
if (!dum->udev) { if (!dum_hcd->udev) {
dum->udev = urb->dev; dum_hcd->udev = urb->dev;
usb_get_dev (dum->udev); usb_get_dev(dum_hcd->udev);
} else if (unlikely (dum->udev != urb->dev)) } else if (unlikely(dum_hcd->udev != urb->dev))
dev_err (dummy_dev(dum), "usb_device address has changed!\n"); dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
list_add_tail (&urbp->urbp_list, &dum->urbp_list); list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
urb->hcpriv = urbp; urb->hcpriv = urbp;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL) if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */ urb->error_count = 1; /* mark as a new urb */
/* kick the scheduler, it'll do the rest */ /* kick the scheduler, it'll do the rest */
if (!timer_pending (&dum->timer)) if (!timer_pending(&dum_hcd->timer))
mod_timer (&dum->timer, jiffies + 1); mod_timer(&dum_hcd->timer, jiffies + 1);
done: done:
spin_unlock_irqrestore(&dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc; return rc;
} }
static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{ {
struct dummy *dum; struct dummy_hcd *dum_hcd;
unsigned long flags; unsigned long flags;
int rc; int rc;
/* giveback happens automatically in timer callback, /* giveback happens automatically in timer callback,
* so make sure the callback happens */ * so make sure the callback happens */
dum = hcd_to_dummy (hcd); dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave(&dum_hcd->dum->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status); rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum->rh_state != DUMMY_RH_RUNNING && if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum->urbp_list)) !list_empty(&dum_hcd->urbp_list))
mod_timer (&dum->timer, jiffies); mod_timer(&dum_hcd->timer, jiffies);
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc; return rc;
} }
...@@ -1185,7 +1201,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) ...@@ -1185,7 +1201,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
return limit; return limit;
} }
#define is_active(dum) ((dum->port_status & \ #define is_active(dum_hcd) ((dum_hcd->port_status & \
(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
USB_PORT_STAT_SUSPEND)) \ USB_PORT_STAT_SUSPEND)) \
== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
...@@ -1194,7 +1210,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) ...@@ -1194,7 +1210,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
{ {
int i; int i;
if (!is_active (dum)) if (!is_active(dum->hs_hcd))
return NULL; return NULL;
if ((address & ~USB_DIR_IN) == 0) if ((address & ~USB_DIR_IN) == 0)
return &dum->ep [0]; return &dum->ep [0];
...@@ -1231,11 +1247,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) ...@@ -1231,11 +1247,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
* 1 - if the request wasn't handles * 1 - if the request wasn't handles
* error code on error * error code on error
*/ */
static int handle_control_request(struct dummy *dum, struct urb *urb, static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
struct usb_ctrlrequest *setup, struct usb_ctrlrequest *setup,
int *status) int *status)
{ {
struct dummy_ep *ep2; struct dummy_ep *ep2;
struct dummy *dum = dum_hcd->dum;
int ret_val = 1; int ret_val = 1;
unsigned w_index; unsigned w_index;
unsigned w_value; unsigned w_value;
...@@ -1354,9 +1371,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb, ...@@ -1354,9 +1371,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
/* drive both sides of the transfers; looks like irq handlers to /* drive both sides of the transfers; looks like irq handlers to
* both drivers except the callbacks aren't in_irq(). * both drivers except the callbacks aren't in_irq().
*/ */
static void dummy_timer (unsigned long _dum) static void dummy_timer(unsigned long _dum_hcd)
{ {
struct dummy *dum = (struct dummy *) _dum; struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd;
struct dummy *dum = dum_hcd->dum;
struct urbp *urbp, *tmp; struct urbp *urbp, *tmp;
unsigned long flags; unsigned long flags;
int limit, total; int limit, total;
...@@ -1374,7 +1392,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1374,7 +1392,7 @@ static void dummy_timer (unsigned long _dum)
total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
break; break;
default: default:
dev_err (dummy_dev(dum), "bogus device speed\n"); dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
return; return;
} }
...@@ -1383,8 +1401,8 @@ static void dummy_timer (unsigned long _dum) ...@@ -1383,8 +1401,8 @@ static void dummy_timer (unsigned long _dum)
/* look at each urb queued by the host side driver */ /* look at each urb queued by the host side driver */
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) { if (!dum_hcd->udev) {
dev_err (dummy_dev(dum), dev_err(dummy_dev(dum_hcd),
"timer fired with no URBs pending?\n"); "timer fired with no URBs pending?\n");
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
return; return;
...@@ -1397,7 +1415,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1397,7 +1415,7 @@ static void dummy_timer (unsigned long _dum)
} }
restart: restart:
list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) { list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
struct urb *urb; struct urb *urb;
struct dummy_request *req; struct dummy_request *req;
u8 address; u8 address;
...@@ -1408,7 +1426,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1408,7 +1426,7 @@ static void dummy_timer (unsigned long _dum)
urb = urbp->urb; urb = urbp->urb;
if (urb->unlinked) if (urb->unlinked)
goto return_urb; goto return_urb;
else if (dum->rh_state != DUMMY_RH_RUNNING) else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
continue; continue;
type = usb_pipetype (urb->pipe); type = usb_pipetype (urb->pipe);
...@@ -1426,7 +1444,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1426,7 +1444,7 @@ static void dummy_timer (unsigned long _dum)
ep = find_endpoint(dum, address); ep = find_endpoint(dum, address);
if (!ep) { if (!ep) {
/* set_configuration() disagreement */ /* set_configuration() disagreement */
dev_dbg (dummy_dev(dum), dev_dbg(dummy_dev(dum_hcd),
"no ep configured for urb %p\n", "no ep configured for urb %p\n",
urb); urb);
status = -EPROTO; status = -EPROTO;
...@@ -1442,7 +1460,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1442,7 +1460,7 @@ static void dummy_timer (unsigned long _dum)
} }
if (ep->halted && !ep->setup_stage) { if (ep->halted && !ep->setup_stage) {
/* NOTE: must not be iso! */ /* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n", dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
ep->ep.name, urb); ep->ep.name, urb);
status = -EPIPE; status = -EPIPE;
goto return_urb; goto return_urb;
...@@ -1477,7 +1495,7 @@ static void dummy_timer (unsigned long _dum) ...@@ -1477,7 +1495,7 @@ static void dummy_timer (unsigned long _dum)
ep->setup_stage = 0; ep->setup_stage = 0;
ep->halted = 0; ep->halted = 0;
value = handle_control_request(dum, urb, &setup, value = handle_control_request(dum_hcd, urb, &setup,
&status); &status);
/* gadget driver handles all other requests. block /* gadget driver handles all other requests. block
...@@ -1547,20 +1565,20 @@ static void dummy_timer (unsigned long _dum) ...@@ -1547,20 +1565,20 @@ static void dummy_timer (unsigned long _dum)
if (ep) if (ep)
ep->already_seen = ep->setup_stage = 0; ep->already_seen = ep->setup_stage = 0;
usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb); usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
spin_unlock (&dum->lock); spin_unlock (&dum->lock);
usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status); usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
spin_lock (&dum->lock); spin_lock (&dum->lock);
goto restart; goto restart;
} }
if (list_empty (&dum->urbp_list)) { if (list_empty(&dum_hcd->urbp_list)) {
usb_put_dev (dum->udev); usb_put_dev(dum_hcd->udev);
dum->udev = NULL; dum_hcd->udev = NULL;
} else if (dum->rh_state == DUMMY_RH_RUNNING) { } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */ /* want a 1 msec delay here */
mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
} }
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore (&dum->lock, flags);
...@@ -1577,32 +1595,32 @@ static void dummy_timer (unsigned long _dum) ...@@ -1577,32 +1595,32 @@ static void dummy_timer (unsigned long _dum)
static int dummy_hub_status (struct usb_hcd *hcd, char *buf) static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
{ {
struct dummy *dum; struct dummy_hcd *dum_hcd;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
dum = hcd_to_dummy (hcd); dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave(&dum_hcd->dum->lock, flags);
if (!HCD_HW_ACCESSIBLE(hcd)) if (!HCD_HW_ACCESSIBLE(hcd))
goto done; goto done;
if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum->port_status &= ~USB_PORT_STAT_SUSPEND; dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
set_link_state (dum); set_link_state(dum_hcd);
} }
if ((dum->port_status & PORT_C_MASK) != 0) { if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
*buf = (1 << 1); *buf = (1 << 1);
dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
dum->port_status); dum_hcd->port_status);
retval = 1; retval = 1;
if (dum->rh_state == DUMMY_RH_SUSPENDED) if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
usb_hcd_resume_root_hub (hcd); usb_hcd_resume_root_hub (hcd);
} }
done: done:
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return retval; return retval;
} }
...@@ -1626,39 +1644,40 @@ static int dummy_hub_control ( ...@@ -1626,39 +1644,40 @@ static int dummy_hub_control (
char *buf, char *buf,
u16 wLength u16 wLength
) { ) {
struct dummy *dum; struct dummy_hcd *dum_hcd;
int retval = 0; int retval = 0;
unsigned long flags; unsigned long flags;
if (!HCD_HW_ACCESSIBLE(hcd)) if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT; return -ETIMEDOUT;
dum = hcd_to_dummy (hcd); dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave (&dum->lock, flags);
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
switch (typeReq) { switch (typeReq) {
case ClearHubFeature: case ClearHubFeature:
break; break;
case ClearPortFeature: case ClearPortFeature:
switch (wValue) { switch (wValue) {
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
if (dum->port_status & USB_PORT_STAT_SUSPEND) { if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
/* 20msec resume signaling */ /* 20msec resume signaling */
dum->resuming = 1; dum_hcd->resuming = 1;
dum->re_timeout = jiffies + dum_hcd->re_timeout = jiffies +
msecs_to_jiffies(20); msecs_to_jiffies(20);
} }
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
if (dum->port_status & USB_PORT_STAT_POWER) if (dum_hcd->port_status & USB_PORT_STAT_POWER)
dev_dbg (dummy_dev(dum), "power-off\n"); dev_dbg(dummy_dev(dum_hcd), "power-off\n");
/* FALLS THROUGH */ /* FALLS THROUGH */
default: default:
dum->port_status &= ~(1 << wValue); dum_hcd->port_status &= ~(1 << wValue);
set_link_state (dum); set_link_state(dum_hcd);
} }
break; break;
case GetHubDescriptor: case GetHubDescriptor:
hub_descriptor ((struct usb_hub_descriptor *) buf); hub_descriptor((struct usb_hub_descriptor *) buf);
break; break;
case GetHubStatus: case GetHubStatus:
*(__le32 *) buf = cpu_to_le32 (0); *(__le32 *) buf = cpu_to_le32 (0);
...@@ -1670,39 +1689,38 @@ static int dummy_hub_control ( ...@@ -1670,39 +1689,38 @@ static int dummy_hub_control (
/* whoever resets or resumes must GetPortStatus to /* whoever resets or resumes must GetPortStatus to
* complete it!! * complete it!!
*/ */
if (dum->resuming && if (dum_hcd->resuming &&
time_after_eq (jiffies, dum->re_timeout)) { time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum->port_status &= ~USB_PORT_STAT_SUSPEND; dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
} }
if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
time_after_eq (jiffies, dum->re_timeout)) { time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_RESET << 16); dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
dum->port_status &= ~USB_PORT_STAT_RESET; dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
if (dum->pullup) { if (dum_hcd->dum->pullup) {
dum->port_status |= USB_PORT_STAT_ENABLE; dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
/* give it the best speed we agree on */ switch (dum_hcd->dum->gadget.speed) {
dum->gadget.speed = dum->driver->speed;
dum->gadget.ep0->maxpacket = 64;
switch (dum->gadget.speed) {
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
dum->port_status |= dum_hcd->port_status |=
USB_PORT_STAT_HIGH_SPEED; USB_PORT_STAT_HIGH_SPEED;
break; break;
case USB_SPEED_LOW: case USB_SPEED_LOW:
dum->gadget.ep0->maxpacket = 8; dum_hcd->dum->gadget.ep0->
dum->port_status |= maxpacket = 8;
dum_hcd->port_status |=
USB_PORT_STAT_LOW_SPEED; USB_PORT_STAT_LOW_SPEED;
break; break;
default: default:
dum->gadget.speed = USB_SPEED_FULL; dum_hcd->dum->gadget.speed =
USB_SPEED_FULL;
break; break;
} }
} }
} }
set_link_state (dum); set_link_state(dum_hcd);
((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
break; break;
case SetHubFeature: case SetHubFeature:
retval = -EPIPE; retval = -EPIPE;
...@@ -1710,87 +1728,91 @@ static int dummy_hub_control ( ...@@ -1710,87 +1728,91 @@ static int dummy_hub_control (
case SetPortFeature: case SetPortFeature:
switch (wValue) { switch (wValue) {
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
if (dum->active) { if (dum_hcd->active) {
dum->port_status |= USB_PORT_STAT_SUSPEND; dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
/* HNP would happen here; for now we /* HNP would happen here; for now we
* assume b_bus_req is always true. * assume b_bus_req is always true.
*/ */
set_link_state (dum); set_link_state(dum_hcd);
if (((1 << USB_DEVICE_B_HNP_ENABLE) if (((1 << USB_DEVICE_B_HNP_ENABLE)
& dum->devstatus) != 0) & dum_hcd->dum->devstatus) != 0)
dev_dbg (dummy_dev(dum), dev_dbg(dummy_dev(dum_hcd),
"no HNP yet!\n"); "no HNP yet!\n");
} }
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
dum->port_status |= USB_PORT_STAT_POWER; dum_hcd->port_status |= USB_PORT_STAT_POWER;
set_link_state (dum); set_link_state(dum_hcd);
break; break;
case USB_PORT_FEAT_RESET: case USB_PORT_FEAT_RESET:
/* if it's already enabled, disable */ /* if it's already enabled, disable */
dum->port_status &= ~(USB_PORT_STAT_ENABLE dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
| USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED); | USB_PORT_STAT_HIGH_SPEED);
dum->devstatus = 0; /*
/* 50msec reset signaling */ * We want to reset device status. All but the
dum->re_timeout = jiffies + msecs_to_jiffies(50); * Self powered feature
*/
dum_hcd->dum->devstatus &=
(1 << USB_DEVICE_SELF_POWERED);
dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
/* FALLS THROUGH */ /* FALLS THROUGH */
default: default:
if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { if ((dum_hcd->port_status &
dum->port_status |= (1 << wValue); USB_PORT_STAT_POWER) != 0) {
set_link_state (dum); dum_hcd->port_status |= (1 << wValue);
set_link_state(dum_hcd);
} }
} }
break; break;
default: default:
dev_dbg (dummy_dev(dum), dev_dbg(dummy_dev(dum_hcd),
"hub control req%04x v%04x i%04x l%d\n", "hub control req%04x v%04x i%04x l%d\n",
typeReq, wValue, wIndex, wLength); typeReq, wValue, wIndex, wLength);
/* "protocol stall" on error */ /* "protocol stall" on error */
retval = -EPIPE; retval = -EPIPE;
} }
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
if ((dum->port_status & PORT_C_MASK) != 0) if ((dum_hcd->port_status & PORT_C_MASK) != 0)
usb_hcd_poll_rh_status (hcd); usb_hcd_poll_rh_status (hcd);
return retval; return retval;
} }
static int dummy_bus_suspend (struct usb_hcd *hcd) static int dummy_bus_suspend (struct usb_hcd *hcd)
{ {
struct dummy *dum = hcd_to_dummy (hcd); struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock); spin_lock_irq(&dum_hcd->dum->lock);
dum->rh_state = DUMMY_RH_SUSPENDED; dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
set_link_state (dum); set_link_state(dum_hcd);
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
spin_unlock_irq (&dum->lock); spin_unlock_irq(&dum_hcd->dum->lock);
return 0; return 0;
} }
static int dummy_bus_resume (struct usb_hcd *hcd) static int dummy_bus_resume (struct usb_hcd *hcd)
{ {
struct dummy *dum = hcd_to_dummy (hcd); struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
int rc = 0; int rc = 0;
dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__); dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock); spin_lock_irq(&dum_hcd->dum->lock);
if (!HCD_HW_ACCESSIBLE(hcd)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
} else { } else {
dum->rh_state = DUMMY_RH_RUNNING; dum_hcd->rh_state = DUMMY_RH_RUNNING;
set_link_state (dum); set_link_state(dum_hcd);
if (!list_empty(&dum->urbp_list)) if (!list_empty(&dum_hcd->urbp_list))
mod_timer (&dum->timer, jiffies); mod_timer(&dum_hcd->timer, jiffies);
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
} }
spin_unlock_irq (&dum->lock); spin_unlock_irq(&dum_hcd->dum->lock);
return rc; return rc;
} }
...@@ -1842,43 +1864,41 @@ static ssize_t ...@@ -1842,43 +1864,41 @@ static ssize_t
show_urbs (struct device *dev, struct device_attribute *attr, char *buf) show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct usb_hcd *hcd = dev_get_drvdata (dev); struct usb_hcd *hcd = dev_get_drvdata (dev);
struct dummy *dum = hcd_to_dummy (hcd); struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
struct urbp *urbp; struct urbp *urbp;
size_t size = 0; size_t size = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave(&dum_hcd->dum->lock, flags);
list_for_each_entry (urbp, &dum->urbp_list, urbp_list) { list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
size_t temp; size_t temp;
temp = show_urb (buf, PAGE_SIZE - size, urbp->urb); temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
buf += temp; buf += temp;
size += temp; size += temp;
} }
spin_unlock_irqrestore (&dum->lock, flags); spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return size; return size;
} }
static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
static int dummy_start (struct usb_hcd *hcd) static int dummy_start(struct usb_hcd *hcd)
{ {
struct dummy *dum; struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
dum = hcd_to_dummy (hcd);
/* /*
* MASTER side init ... we emulate a root hub that'll only ever * MASTER side init ... we emulate a root hub that'll only ever
* talk to one device (the slave side). Also appears in sysfs, * talk to one device (the slave side). Also appears in sysfs,
* just like more familiar pci-based HCDs. * just like more familiar pci-based HCDs.
*/ */
spin_lock_init (&dum->lock); spin_lock_init(&dum_hcd->dum->lock);
init_timer (&dum->timer); init_timer(&dum_hcd->timer);
dum->timer.function = dummy_timer; dum_hcd->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum; dum_hcd->timer.data = (unsigned long)dum_hcd;
dum->rh_state = DUMMY_RH_RUNNING; dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD (&dum->urbp_list); INIT_LIST_HEAD(&dum_hcd->urbp_list);
hcd->power_budget = POWER_BUDGET; hcd->power_budget = POWER_BUDGET;
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
...@@ -1889,17 +1909,17 @@ static int dummy_start (struct usb_hcd *hcd) ...@@ -1889,17 +1909,17 @@ static int dummy_start (struct usb_hcd *hcd)
#endif #endif
/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
return device_create_file (dummy_dev(dum), &dev_attr_urbs); return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
} }
static void dummy_stop (struct usb_hcd *hcd) static void dummy_stop (struct usb_hcd *hcd)
{ {
struct dummy *dum; struct dummy *dum;
dum = hcd_to_dummy (hcd); dum = (hcd_to_dummy_hcd(hcd))->dum;
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
device_remove_file (dummy_dev(dum), &dev_attr_urbs); usb_gadget_unregister_driver(dum->driver);
dev_info (dummy_dev(dum), "stopped\n"); dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1909,13 +1929,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd) ...@@ -1909,13 +1929,26 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)
return dummy_g_get_frame (NULL); return dummy_g_get_frame (NULL);
} }
static int dummy_setup(struct usb_hcd *hcd)
{
if (usb_hcd_is_primary_hcd(hcd)) {
the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
the_controller.hs_hcd->dum = &the_controller;
/* Mark the first roothub as being USB 2.0. */
hcd->speed = HCD_USB2;
hcd->self.root_hub->speed = USB_SPEED_HIGH;
}
return 0;
}
static const struct hc_driver dummy_hcd = { static const struct hc_driver dummy_hcd = {
.description = (char *) driver_name, .description = (char *) driver_name,
.product_desc = "Dummy host controller", .product_desc = "Dummy host controller",
.hcd_priv_size = sizeof(struct dummy), .hcd_priv_size = sizeof(struct dummy_hcd),
.flags = HCD_USB2, .flags = HCD_USB2,
.reset = dummy_setup,
.start = dummy_start, .start = dummy_start,
.stop = dummy_stop, .stop = dummy_stop,
...@@ -1932,47 +1965,47 @@ static const struct hc_driver dummy_hcd = { ...@@ -1932,47 +1965,47 @@ static const struct hc_driver dummy_hcd = {
static int dummy_hcd_probe(struct platform_device *pdev) static int dummy_hcd_probe(struct platform_device *pdev)
{ {
struct usb_hcd *hcd; struct usb_hcd *hs_hcd;
int retval; int retval;
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) if (!hs_hcd)
return -ENOMEM; return -ENOMEM;
the_controller = hcd_to_dummy (hcd); hs_hcd->has_tt = 1;
hcd->has_tt = 1;
retval = usb_add_hcd(hcd, 0, 0); retval = usb_add_hcd(hs_hcd, 0, 0);
if (retval != 0) { if (retval != 0) {
usb_put_hcd (hcd); usb_put_hcd(hs_hcd);
the_controller = NULL; the_controller.hs_hcd = NULL;
} }
return retval; return retval;
} }
static int dummy_hcd_remove (struct platform_device *pdev) static int dummy_hcd_remove(struct platform_device *pdev)
{ {
struct usb_hcd *hcd; struct dummy *dum;
dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
the_controller.hs_hcd = NULL;
hcd = platform_get_drvdata (pdev);
usb_remove_hcd (hcd);
usb_put_hcd (hcd);
the_controller = NULL;
return 0; return 0;
} }
static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state) static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
struct dummy *dum; struct dummy_hcd *dum_hcd;
int rc = 0; int rc = 0;
dev_dbg (&pdev->dev, "%s\n", __func__); dev_dbg (&pdev->dev, "%s\n", __func__);
hcd = platform_get_drvdata (pdev); hcd = platform_get_drvdata (pdev);
dum = hcd_to_dummy (hcd); dum_hcd = hcd_to_dummy_hcd(hcd);
if (dum->rh_state == DUMMY_RH_RUNNING) { if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
rc = -EBUSY; rc = -EBUSY;
} else } else
...@@ -2032,7 +2065,7 @@ static int __init init (void) ...@@ -2032,7 +2065,7 @@ static int __init init (void)
retval = platform_device_add(the_hcd_pdev); retval = platform_device_add(the_hcd_pdev);
if (retval < 0) if (retval < 0)
goto err_add_hcd; goto err_add_hcd;
if (!the_controller) { if (!the_controller.hs_hcd) {
/* /*
* The hcd was added successfully but its probe function failed * The hcd was added successfully but its probe function failed
* for some reason. * for some reason.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment