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 {
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 {
spinlock_t lock;
......@@ -167,36 +183,26 @@ struct dummy {
u16 devstatus;
unsigned udc_suspended:1;
unsigned pullup:1;
unsigned active:1;
unsigned old_active:1;
/*
* MASTER/HOST side support
*/
enum dummy_rh_state rh_state;
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;
struct dummy_hcd *hs_hcd;
};
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);
}
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)
......@@ -209,9 +215,10 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
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)
......@@ -219,7 +226,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *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)
}
/* caller must hold lock */
static void
set_link_state (struct dummy *dum)
static void set_link_state(struct dummy_hcd *dum_hcd)
{
dum->active = 0;
if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
dum->port_status = 0;
struct dummy *dum = dum_hcd->dum;
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 */
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_LOW_SPEED |
USB_PORT_STAT_HIGH_SPEED |
USB_PORT_STAT_SUSPEND);
if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0)
dum_hcd->port_status |=
(USB_PORT_STAT_C_CONNECTION << 16);
} else {
dum->port_status |= USB_PORT_STAT_CONNECTION;
if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
dum->port_status &= ~USB_PORT_STAT_SUSPEND;
else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum->rh_state != DUMMY_RH_SUSPENDED)
dum->active = 1;
}
if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
dum->resuming = 0;
if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
(dum->port_status & USB_PORT_STAT_RESET) != 0) {
if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) == 0)
dum_hcd->port_status |=
(USB_PORT_STAT_C_CONNECTION << 16);
if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
else if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
dum_hcd->active = 1;
}
if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
dum_hcd->active)
dum_hcd->resuming = 0;
if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 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) {
stop_activity (dum);
spin_unlock (&dum->lock);
dum->driver->disconnect (&dum->gadget);
spin_lock (&dum->lock);
}
} else if (dum->active != dum->old_active) {
if (dum->old_active && dum->driver->suspend) {
} else if (dum_hcd->active != dum_hcd->old_active) {
if (dum_hcd->old_active && dum->driver->suspend) {
spin_unlock (&dum->lock);
dum->driver->suspend (&dum->gadget);
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);
dum->driver->resume (&dum->gadget);
spin_lock (&dum->lock);
}
}
dum->old_status = dum->port_status;
dum->old_active = dum->active;
dum_hcd->old_status = dum_hcd->port_status;
dum_hcd->old_active = dum_hcd->active;
}
/*-------------------------------------------------------------------------*/
......@@ -332,6 +343,7 @@ static int
dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{
struct dummy *dum;
struct dummy_hcd *dum_hcd;
struct dummy_ep *ep;
unsigned max;
int retval;
......@@ -341,9 +353,17 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
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;
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
* (hardware or its drivers) may not check. some endpoints
......@@ -515,6 +535,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
struct dummy_ep *ep;
struct dummy_request *req;
struct dummy *dum;
struct dummy_hcd *dum_hcd;
unsigned long flags;
req = usb_request_to_dummy_request (_req);
......@@ -526,7 +547,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
return -EINVAL;
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;
#if 0
......@@ -670,24 +692,24 @@ static int dummy_g_get_frame (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);
if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE)
dum_hcd = gadget_to_dummy_hcd(_gadget);
if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
| (1 << USB_DEVICE_REMOTE_WAKEUP))))
return -EINVAL;
if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
return -ENOLINK;
if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum->rh_state != DUMMY_RH_SUSPENDED)
if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
return -EIO;
/* FIXME: What if the root hub is suspended but the port isn't? */
/* hub notices our request, issues downstream resume, etc */
dum->resuming = 1;
dum->re_timeout = jiffies + msecs_to_jiffies(20);
mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
dum_hcd->resuming = 1;
dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
return 0;
}
......@@ -695,7 +717,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
dum = gadget_to_dummy (_gadget);
dum = (gadget_to_dummy_hcd(_gadget))->dum;
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
......@@ -708,13 +730,12 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
struct dummy *dum;
unsigned long flags;
dum = gadget_to_dummy (_gadget);
dum = gadget_to_dummy_hcd(_gadget)->dum;
spin_lock_irqsave (&dum->lock, flags);
dum->pullup = (value != 0);
set_link_state (dum);
set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags);
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0;
}
......@@ -764,7 +785,7 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
static int dummy_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct dummy *dum = the_controller;
struct dummy *dum = &the_controller;
int retval, i;
if (!dum)
......@@ -800,7 +821,8 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
}
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);
INIT_LIST_HEAD(&dum->fifo_req.queue);
......@@ -819,16 +841,18 @@ static int dummy_udc_start(struct usb_gadget_driver *driver,
/* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock);
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);
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0;
}
static int dummy_udc_stop(struct usb_gadget_driver *driver)
{
struct dummy *dum = the_controller;
struct dummy *dum = &the_controller;
unsigned long flags;
if (!dum)
......@@ -841,7 +865,7 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
spin_lock_irqsave (&dum->lock, flags);
dum->pullup = 0;
set_link_state (dum);
set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags);
driver->unbind (&dum->gadget);
......@@ -850,10 +874,9 @@ static int dummy_udc_stop(struct usb_gadget_driver *driver)
spin_lock_irqsave (&dum->lock, flags);
dum->pullup = 0;
set_link_state (dum);
set_link_state(dum->hs_hcd);
spin_unlock_irqrestore (&dum->lock, flags);
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum->hs_hcd));
return 0;
}
......@@ -874,25 +897,18 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
static void
dummy_gadget_release (struct device *dev)
{
struct dummy *dum = gadget_dev_to_dummy (dev);
usb_put_hcd (dummy_to_hcd (dum));
return;
}
static int dummy_udc_probe (struct platform_device *pdev)
{
struct dummy *dum = the_controller;
struct dummy *dum = &the_controller;
int rc;
usb_get_hcd(dummy_to_hcd(dum));
dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops;
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");
dum->gadget.dev.parent = &pdev->dev;
dum->gadget.dev.release = dummy_gadget_release;
......@@ -937,10 +953,10 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
dum->udc_suspended = 1;
set_link_state (dum);
set_link_state(dum->hs_hcd);
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;
}
......@@ -951,10 +967,10 @@ static int dummy_udc_resume (struct platform_device *pdev)
dev_dbg (&pdev->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
dum->udc_suspended = 0;
set_link_state (dum);
set_link_state(dum->hs_hcd);
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;
}
......@@ -988,7 +1004,7 @@ static int dummy_urb_enqueue (
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct dummy_hcd *dum_hcd;
struct urbp *urbp;
unsigned long flags;
int rc;
......@@ -1001,51 +1017,51 @@ static int dummy_urb_enqueue (
return -ENOMEM;
urbp->urb = urb;
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) {
kfree(urbp);
goto done;
}
if (!dum->udev) {
dum->udev = urb->dev;
usb_get_dev (dum->udev);
} else if (unlikely (dum->udev != urb->dev))
dev_err (dummy_dev(dum), "usb_device address has changed!\n");
if (!dum_hcd->udev) {
dum_hcd->udev = urb->dev;
usb_get_dev(dum_hcd->udev);
} else if (unlikely(dum_hcd->udev != urb->dev))
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;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */
/* kick the scheduler, it'll do the rest */
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
if (!timer_pending(&dum_hcd->timer))
mod_timer(&dum_hcd->timer, jiffies + 1);
done:
spin_unlock_irqrestore(&dum->lock, flags);
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc;
}
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;
int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum_hcd->urbp_list))
mod_timer(&dum_hcd->timer, jiffies);
spin_unlock_irqrestore (&dum->lock, flags);
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return rc;
}
......@@ -1185,7 +1201,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
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_SUSPEND)) \
== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
......@@ -1194,7 +1210,7 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
{
int i;
if (!is_active (dum))
if (!is_active(dum->hs_hcd))
return NULL;
if ((address & ~USB_DIR_IN) == 0)
return &dum->ep [0];
......@@ -1231,11 +1247,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
* 1 - if the request wasn't handles
* 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,
int *status)
{
struct dummy_ep *ep2;
struct dummy *dum = dum_hcd->dum;
int ret_val = 1;
unsigned w_index;
unsigned w_value;
......@@ -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
* 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;
unsigned long flags;
int limit, total;
......@@ -1374,7 +1392,7 @@ static void dummy_timer (unsigned long _dum)
total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
break;
default:
dev_err (dummy_dev(dum), "bogus device speed\n");
dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
return;
}
......@@ -1383,8 +1401,8 @@ static void dummy_timer (unsigned long _dum)
/* look at each urb queued by the host side driver */
spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) {
dev_err (dummy_dev(dum),
if (!dum_hcd->udev) {
dev_err(dummy_dev(dum_hcd),
"timer fired with no URBs pending?\n");
spin_unlock_irqrestore (&dum->lock, flags);
return;
......@@ -1397,7 +1415,7 @@ static void dummy_timer (unsigned long _dum)
}
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 dummy_request *req;
u8 address;
......@@ -1408,7 +1426,7 @@ static void dummy_timer (unsigned long _dum)
urb = urbp->urb;
if (urb->unlinked)
goto return_urb;
else if (dum->rh_state != DUMMY_RH_RUNNING)
else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
......@@ -1426,7 +1444,7 @@ static void dummy_timer (unsigned long _dum)
ep = find_endpoint(dum, address);
if (!ep) {
/* set_configuration() disagreement */
dev_dbg (dummy_dev(dum),
dev_dbg(dummy_dev(dum_hcd),
"no ep configured for urb %p\n",
urb);
status = -EPROTO;
......@@ -1442,7 +1460,7 @@ static void dummy_timer (unsigned long _dum)
}
if (ep->halted && !ep->setup_stage) {
/* 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);
status = -EPIPE;
goto return_urb;
......@@ -1477,7 +1495,7 @@ static void dummy_timer (unsigned long _dum)
ep->setup_stage = 0;
ep->halted = 0;
value = handle_control_request(dum, urb, &setup,
value = handle_control_request(dum_hcd, urb, &setup,
&status);
/* gadget driver handles all other requests. block
......@@ -1547,20 +1565,20 @@ static void dummy_timer (unsigned long _dum)
if (ep)
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);
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);
goto restart;
}
if (list_empty (&dum->urbp_list)) {
usb_put_dev (dum->udev);
dum->udev = NULL;
} else if (dum->rh_state == DUMMY_RH_RUNNING) {
if (list_empty(&dum_hcd->urbp_list)) {
usb_put_dev(dum_hcd->udev);
dum_hcd->udev = NULL;
} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* 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);
......@@ -1577,32 +1595,32 @@ static void dummy_timer (unsigned long _dum)
static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
{
struct dummy *dum;
struct dummy_hcd *dum_hcd;
unsigned long flags;
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))
goto done;
if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum->port_status &= ~USB_PORT_STAT_SUSPEND;
set_link_state (dum);
if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
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);
dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
dum->port_status);
dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
dum_hcd->port_status);
retval = 1;
if (dum->rh_state == DUMMY_RH_SUSPENDED)
if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
usb_hcd_resume_root_hub (hcd);
}
done:
spin_unlock_irqrestore (&dum->lock, flags);
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return retval;
}
......@@ -1626,39 +1644,40 @@ static int dummy_hub_control (
char *buf,
u16 wLength
) {
struct dummy *dum;
struct dummy_hcd *dum_hcd;
int retval = 0;
unsigned long flags;
if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT;
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
switch (typeReq) {
case ClearHubFeature:
break;
case ClearPortFeature:
switch (wValue) {
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 */
dum->resuming = 1;
dum->re_timeout = jiffies +
dum_hcd->resuming = 1;
dum_hcd->re_timeout = jiffies +
msecs_to_jiffies(20);
}
break;
case USB_PORT_FEAT_POWER:
if (dum->port_status & USB_PORT_STAT_POWER)
dev_dbg (dummy_dev(dum), "power-off\n");
if (dum_hcd->port_status & USB_PORT_STAT_POWER)
dev_dbg(dummy_dev(dum_hcd), "power-off\n");
/* FALLS THROUGH */
default:
dum->port_status &= ~(1 << wValue);
set_link_state (dum);
dum_hcd->port_status &= ~(1 << wValue);
set_link_state(dum_hcd);
}
break;
case GetHubDescriptor:
hub_descriptor ((struct usb_hub_descriptor *) buf);
hub_descriptor((struct usb_hub_descriptor *) buf);
break;
case GetHubStatus:
*(__le32 *) buf = cpu_to_le32 (0);
......@@ -1670,39 +1689,38 @@ static int dummy_hub_control (
/* whoever resets or resumes must GetPortStatus to
* complete it!!
*/
if (dum->resuming &&
time_after_eq (jiffies, dum->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum->port_status &= ~USB_PORT_STAT_SUSPEND;
}
if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
time_after_eq (jiffies, dum->re_timeout)) {
dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
dum->port_status &= ~USB_PORT_STAT_RESET;
if (dum->pullup) {
dum->port_status |= USB_PORT_STAT_ENABLE;
/* give it the best speed we agree on */
dum->gadget.speed = dum->driver->speed;
dum->gadget.ep0->maxpacket = 64;
switch (dum->gadget.speed) {
if (dum_hcd->resuming &&
time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
}
if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
time_after_eq(jiffies, dum_hcd->re_timeout)) {
dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
if (dum_hcd->dum->pullup) {
dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
switch (dum_hcd->dum->gadget.speed) {
case USB_SPEED_HIGH:
dum->port_status |=
dum_hcd->port_status |=
USB_PORT_STAT_HIGH_SPEED;
break;
case USB_SPEED_LOW:
dum->gadget.ep0->maxpacket = 8;
dum->port_status |=
dum_hcd->dum->gadget.ep0->
maxpacket = 8;
dum_hcd->port_status |=
USB_PORT_STAT_LOW_SPEED;
break;
default:
dum->gadget.speed = USB_SPEED_FULL;
dum_hcd->dum->gadget.speed =
USB_SPEED_FULL;
break;
}
}
}
set_link_state (dum);
((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
set_link_state(dum_hcd);
((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
break;
case SetHubFeature:
retval = -EPIPE;
......@@ -1710,87 +1728,91 @@ static int dummy_hub_control (
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
if (dum->active) {
dum->port_status |= USB_PORT_STAT_SUSPEND;
if (dum_hcd->active) {
dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
/* HNP would happen here; for now we
* assume b_bus_req is always true.
*/
set_link_state (dum);
set_link_state(dum_hcd);
if (((1 << USB_DEVICE_B_HNP_ENABLE)
& dum->devstatus) != 0)
dev_dbg (dummy_dev(dum),
& dum_hcd->dum->devstatus) != 0)
dev_dbg(dummy_dev(dum_hcd),
"no HNP yet!\n");
}
break;
case USB_PORT_FEAT_POWER:
dum->port_status |= USB_PORT_STAT_POWER;
set_link_state (dum);
dum_hcd->port_status |= USB_PORT_STAT_POWER;
set_link_state(dum_hcd);
break;
case USB_PORT_FEAT_RESET:
/* 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_HIGH_SPEED);
dum->devstatus = 0;
/* 50msec reset signaling */
dum->re_timeout = jiffies + msecs_to_jiffies(50);
/*
* We want to reset device status. All but the
* Self powered feature
*/
dum_hcd->dum->devstatus &=
(1 << USB_DEVICE_SELF_POWERED);
dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
/* FALLS THROUGH */
default:
if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
dum->port_status |= (1 << wValue);
set_link_state (dum);
if ((dum_hcd->port_status &
USB_PORT_STAT_POWER) != 0) {
dum_hcd->port_status |= (1 << wValue);
set_link_state(dum_hcd);
}
}
break;
default:
dev_dbg (dummy_dev(dum),
dev_dbg(dummy_dev(dum_hcd),
"hub control req%04x v%04x i%04x l%d\n",
typeReq, wValue, wIndex, wLength);
/* "protocol stall" on error */
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);
return retval;
}
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__);
spin_lock_irq (&dum->lock);
dum->rh_state = DUMMY_RH_SUSPENDED;
set_link_state (dum);
spin_lock_irq(&dum_hcd->dum->lock);
dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
set_link_state(dum_hcd);
hcd->state = HC_STATE_SUSPENDED;
spin_unlock_irq (&dum->lock);
spin_unlock_irq(&dum_hcd->dum->lock);
return 0;
}
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;
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)) {
rc = -ESHUTDOWN;
} else {
dum->rh_state = DUMMY_RH_RUNNING;
set_link_state (dum);
if (!list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
set_link_state(dum_hcd);
if (!list_empty(&dum_hcd->urbp_list))
mod_timer(&dum_hcd->timer, jiffies);
hcd->state = HC_STATE_RUNNING;
}
spin_unlock_irq (&dum->lock);
spin_unlock_irq(&dum_hcd->dum->lock);
return rc;
}
......@@ -1842,43 +1864,41 @@ static ssize_t
show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
{
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;
size_t size = 0;
unsigned long flags;
spin_lock_irqsave (&dum->lock, flags);
list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
size_t temp;
temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
buf += temp;
size += temp;
}
spin_unlock_irqrestore (&dum->lock, flags);
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
return size;
}
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;
dum = hcd_to_dummy (hcd);
struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
/*
* MASTER side init ... we emulate a root hub that'll only ever
* talk to one device (the slave side). Also appears in sysfs,
* just like more familiar pci-based HCDs.
*/
spin_lock_init (&dum->lock);
init_timer (&dum->timer);
dum->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum;
dum->rh_state = DUMMY_RH_RUNNING;
spin_lock_init(&dum_hcd->dum->lock);
init_timer(&dum_hcd->timer);
dum_hcd->timer.function = dummy_timer;
dum_hcd->timer.data = (unsigned long)dum_hcd;
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->state = HC_STATE_RUNNING;
......@@ -1889,17 +1909,17 @@ static int dummy_start (struct usb_hcd *hcd)
#endif
/* 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)
{
struct dummy *dum;
dum = hcd_to_dummy (hcd);
device_remove_file (dummy_dev(dum), &dev_attr_urbs);
dev_info (dummy_dev(dum), "stopped\n");
dum = (hcd_to_dummy_hcd(hcd))->dum;
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
usb_gadget_unregister_driver(dum->driver);
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)
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 = {
.description = (char *) driver_name,
.product_desc = "Dummy host controller",
.hcd_priv_size = sizeof(struct dummy),
.hcd_priv_size = sizeof(struct dummy_hcd),
.flags = HCD_USB2,
.reset = dummy_setup,
.start = dummy_start,
.stop = dummy_stop,
......@@ -1932,47 +1965,47 @@ static const struct hc_driver dummy_hcd = {
static int dummy_hcd_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct usb_hcd *hs_hcd;
int retval;
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
if (!hcd)
hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
if (!hs_hcd)
return -ENOMEM;
the_controller = hcd_to_dummy (hcd);
hcd->has_tt = 1;
hs_hcd->has_tt = 1;
retval = usb_add_hcd(hcd, 0, 0);
retval = usb_add_hcd(hs_hcd, 0, 0);
if (retval != 0) {
usb_put_hcd (hcd);
the_controller = NULL;
usb_put_hcd(hs_hcd);
the_controller.hs_hcd = NULL;
}
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;
}
static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd;
struct dummy *dum;
struct dummy_hcd *dum_hcd;
int rc = 0;
dev_dbg (&pdev->dev, "%s\n", __func__);
hcd = platform_get_drvdata (pdev);
dum = hcd_to_dummy (hcd);
if (dum->rh_state == DUMMY_RH_RUNNING) {
dum_hcd = hcd_to_dummy_hcd(hcd);
if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
rc = -EBUSY;
} else
......@@ -2032,7 +2065,7 @@ static int __init init (void)
retval = platform_device_add(the_hcd_pdev);
if (retval < 0)
goto err_add_hcd;
if (!the_controller) {
if (!the_controller.hs_hcd) {
/*
* The hcd was added successfully but its probe function failed
* 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