2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2001-2002 by David Brownell
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
2008-10-30 05:25:50 +08:00
|
|
|
#ifndef __USB_CORE_HCD_H
|
|
|
|
#define __USB_CORE_HCD_H
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
|
2007-10-11 04:27:07 +08:00
|
|
|
#include <linux/rwsem.h>
|
|
|
|
|
2008-06-12 15:49:47 +08:00
|
|
|
#define MAX_TOPO_LEVEL 6
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* This file contains declarations of usbcore internals that are mostly
|
|
|
|
* used or exposed by Host Controller Drivers.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* USB Packet IDs (PIDs)
|
|
|
|
*/
|
2008-02-11 04:24:00 +08:00
|
|
|
#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
|
2005-04-17 06:20:36 +08:00
|
|
|
#define USB_PID_OUT 0xe1
|
|
|
|
#define USB_PID_ACK 0xd2
|
|
|
|
#define USB_PID_DATA0 0xc3
|
|
|
|
#define USB_PID_PING 0xb4 /* USB 2.0 */
|
|
|
|
#define USB_PID_SOF 0xa5
|
|
|
|
#define USB_PID_NYET 0x96 /* USB 2.0 */
|
|
|
|
#define USB_PID_DATA2 0x87 /* USB 2.0 */
|
|
|
|
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
|
|
|
|
#define USB_PID_IN 0x69
|
|
|
|
#define USB_PID_NAK 0x5a
|
|
|
|
#define USB_PID_DATA1 0x4b
|
|
|
|
#define USB_PID_PREAMBLE 0x3c /* Token mode */
|
|
|
|
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
|
|
|
|
#define USB_PID_SETUP 0x2d
|
|
|
|
#define USB_PID_STALL 0x1e
|
|
|
|
#define USB_PID_MDATA 0x0f /* USB 2.0 */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* USB Host Controller Driver (usb_hcd) framework
|
|
|
|
*
|
|
|
|
* Since "struct usb_bus" is so thin, you can't share much code in it.
|
|
|
|
* This framework is a layer over that, and should be more sharable.
|
2007-08-01 11:33:58 +08:00
|
|
|
*
|
|
|
|
* @authorized_default: Specifies if new devices are authorized to
|
|
|
|
* connect by default or they require explicit
|
|
|
|
* user space authorization; this bit is settable
|
|
|
|
* through /sys/class/usb_host/X/authorized_default.
|
|
|
|
* For the rest is RO, so we don't lock to r/w it.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
2006-08-30 23:32:52 +08:00
|
|
|
struct usb_hcd {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* housekeeping
|
|
|
|
*/
|
|
|
|
struct usb_bus self; /* hcd is-a bus */
|
2006-08-30 23:32:52 +08:00
|
|
|
struct kref kref; /* reference counter */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
const char *product_desc; /* product/vendor string */
|
|
|
|
char irq_descr[24]; /* driver + bus # */
|
|
|
|
|
2005-04-22 03:56:37 +08:00
|
|
|
struct timer_list rh_timer; /* drives root-hub polling */
|
|
|
|
struct urb *status_urb; /* the current status urb */
|
2010-01-09 01:57:28 +08:00
|
|
|
#ifdef CONFIG_USB_SUSPEND
|
2007-03-14 04:37:30 +08:00
|
|
|
struct work_struct wakeup_work; /* for remote wakeup */
|
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* hardware info/state
|
|
|
|
*/
|
|
|
|
const struct hc_driver *driver; /* hw-specific hooks */
|
[PATCH] USB: Fix USB suspend/resume crasher (#2)
This patch closes the IRQ race and makes various other OHCI & EHCI code
path safer vs. suspend/resume.
I've been able to (finally !) successfully suspend and resume various
Mac models, with or without USB mouse plugged, or plugging while asleep,
or unplugging while asleep etc... all without a crash.
Alan, please verify the UHCI bit I did, I only verified that it builds.
It's very simple so I wouldn't expect any issue there. If you aren't
confident, then just drop the hunks that change uhci-hcd.c
I also made the patch a little bit more "safer" by making sure the store
to the interrupt register that disables interrupts is not posted before
I set the flag and drop the spinlock.
Without this patch, you cannot reliably sleep/wakeup any recent Mac, and
I suspect PCs have some more sneaky issues too (they don't frankly crash
with machine checks because x86 tend to silently swallow PCI errors but
that won't last afaik, at least PCI Express will blow up in those
situations, but the USB code may still misbehave).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2005-11-25 06:59:46 +08:00
|
|
|
|
|
|
|
/* Flags that need to be manipulated atomically */
|
|
|
|
unsigned long flags;
|
|
|
|
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
|
|
|
|
#define HCD_FLAG_SAW_IRQ 0x00000002
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned rh_registered:1;/* is root hub registered? */
|
|
|
|
|
2005-04-22 03:56:37 +08:00
|
|
|
/* The next flag is a stopgap, to be removed when all the HCDs
|
|
|
|
* support the new root-hub polling mechanism. */
|
|
|
|
unsigned uses_new_polling:1;
|
|
|
|
unsigned poll_rh:1; /* poll for rh status? */
|
|
|
|
unsigned poll_pending:1; /* status has changed? */
|
2006-08-26 10:35:29 +08:00
|
|
|
unsigned wireless:1; /* Wireless USB HCD */
|
2007-08-01 11:33:58 +08:00
|
|
|
unsigned authorized_default:1;
|
2008-04-04 06:02:56 +08:00
|
|
|
unsigned has_tt:1; /* Integrated TT in root hub */
|
2005-04-22 03:56:37 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int irq; /* irq allocated */
|
|
|
|
void __iomem *regs; /* device memory/io */
|
|
|
|
u64 rsrc_start; /* memory/io resource start */
|
|
|
|
u64 rsrc_len; /* memory/io resource length */
|
2005-04-25 23:18:32 +08:00
|
|
|
unsigned power_budget; /* in mA, 0 = no limit */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
USB: Check bandwidth when switching alt settings.
Make the USB core check the bandwidth when switching from one
interface alternate setting to another. Also check the bandwidth
when resetting a configuration (so that alt setting 0 is used). If
this check fails, the device's state is unchanged. If the device
refuses the new alt setting, re-instate the old alt setting in the
host controller hardware.
If a USB device doesn't have an alternate interface setting 0, install
the first alt setting in its descriptors when a new configuration is
requested, or the device is reset.
Add a mutex per root hub to protect bandwidth operations:
adding/reseting/changing configurations, and changing alternate interface
settings. We want to ensure that the xHCI host controller and the USB
device are set up for the same configurations and alternate settings.
There are two (possibly three) steps to do this:
1. The host controller needs to check that bandwidth is available for a
different setting, by issuing and waiting for a configure endpoint
command.
2. Once that returns successfully, a control message is sent to the
device.
3. If that fails, the host controller must be notified through another
configure endpoint command.
The mutex is used to make these three operations seem atomic, to prevent
another driver from using more bandwidth for a different device while
we're in the middle of these operations.
While we're touching the bandwidth code, rename usb_hcd_check_bandwidth()
to usb_hcd_alloc_bandwidth(). This function does more than just check
that the bandwidth change won't exceed the bus bandwidth; it actually
changes the bandwidth configuration in the xHCI host controller.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-12-04 01:44:36 +08:00
|
|
|
/* bandwidth_mutex should be taken before adding or removing
|
|
|
|
* any new bus bandwidth constraints:
|
|
|
|
* 1. Before adding a configuration for a new device.
|
|
|
|
* 2. Before removing the configuration to put the device into
|
|
|
|
* the addressed state.
|
|
|
|
* 3. Before selecting a different configuration.
|
|
|
|
* 4. Before selecting an alternate interface setting.
|
|
|
|
*
|
|
|
|
* bandwidth_mutex should be dropped after a successful control message
|
|
|
|
* to the device, or resetting the bandwidth after a failed attempt.
|
|
|
|
*/
|
|
|
|
struct mutex bandwidth_mutex;
|
|
|
|
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#define HCD_BUFFER_POOLS 4
|
2010-05-18 01:58:12 +08:00
|
|
|
struct dma_pool *pool[HCD_BUFFER_POOLS];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
int state;
|
|
|
|
# define __ACTIVE 0x01
|
|
|
|
# define __SUSPEND 0x04
|
|
|
|
# define __TRANSIENT 0x80
|
|
|
|
|
|
|
|
# define HC_STATE_HALT 0
|
|
|
|
# define HC_STATE_RUNNING (__ACTIVE)
|
|
|
|
# define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
|
|
|
|
# define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
|
|
|
|
# define HC_STATE_SUSPENDED (__SUSPEND)
|
|
|
|
|
|
|
|
#define HC_IS_RUNNING(state) ((state) & __ACTIVE)
|
|
|
|
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
|
|
|
|
|
|
|
|
/* more shared queuing code would be good; it should support
|
|
|
|
* smarter scheduling, handle transaction translators, etc;
|
2008-01-31 07:21:33 +08:00
|
|
|
* input size of periodic table to an interrupt scheduler.
|
2005-04-17 06:20:36 +08:00
|
|
|
* (ohci 32, uhci 1024, ehci 256/512/1024).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The HC driver's private data is stored at the end of
|
|
|
|
* this structure.
|
|
|
|
*/
|
|
|
|
unsigned long hcd_priv[0]
|
2008-01-31 07:21:33 +08:00
|
|
|
__attribute__ ((aligned(sizeof(unsigned long))));
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 2.4 does this a bit differently ... */
|
2008-01-31 07:21:33 +08:00
|
|
|
static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
return &hcd->self;
|
|
|
|
}
|
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
|
2006-08-30 23:32:52 +08:00
|
|
|
{
|
|
|
|
return container_of(bus, struct usb_hcd, self);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
struct hcd_timeout { /* timeouts we allocate */
|
|
|
|
struct list_head timeout_list;
|
|
|
|
struct timer_list timer;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
|
|
struct hc_driver {
|
|
|
|
const char *description; /* "ehci-hcd" etc */
|
|
|
|
const char *product_desc; /* product/vendor string */
|
|
|
|
size_t hcd_priv_size; /* size of private data */
|
|
|
|
|
|
|
|
/* irq handler */
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
|
|
|
irqreturn_t (*irq) (struct usb_hcd *hcd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
int flags;
|
|
|
|
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
|
2008-01-23 14:58:35 +08:00
|
|
|
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
|
2005-04-17 06:20:36 +08:00
|
|
|
#define HCD_USB11 0x0010 /* USB 1.1 */
|
|
|
|
#define HCD_USB2 0x0020 /* USB 2.0 */
|
2009-04-28 10:52:28 +08:00
|
|
|
#define HCD_USB3 0x0040 /* USB 3.0 */
|
2009-04-28 10:54:10 +08:00
|
|
|
#define HCD_MASK 0x0070
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* called to init HCD and root hub */
|
|
|
|
int (*reset) (struct usb_hcd *hcd);
|
|
|
|
int (*start) (struct usb_hcd *hcd);
|
|
|
|
|
|
|
|
/* NOTE: these suspend/resume calls relate to the HC as
|
2005-09-23 13:38:16 +08:00
|
|
|
* a whole, not just the root hub; they're for PCI bus glue.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2005-09-23 13:38:16 +08:00
|
|
|
/* called after suspending the hub, before entering D3 etc */
|
2009-04-28 01:33:41 +08:00
|
|
|
int (*pci_suspend)(struct usb_hcd *hcd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-09-23 13:38:16 +08:00
|
|
|
/* called after entering D0 (etc), before resuming the hub */
|
2009-04-28 01:33:41 +08:00
|
|
|
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* cleanly make HCD stop writing memory and doing I/O */
|
|
|
|
void (*stop) (struct usb_hcd *hcd);
|
|
|
|
|
USB: Properly unregister reboot notifier in case of failure in ehci hcd
If some problem occurs during ehci startup, for instance, request_irq fails,
echi hcd driver tries it best to cleanup, but fails to unregister reboot
notifier, which in turn leads to crash on reboot/poweroff.
The following patch resolves this problem by not using reboot notifiers
anymore, but instead making ehci/ohci driver get its own shutdown method. For
PCI, it is done through pci glue, for everything else through platform driver
glue.
One downside: sa1111 does not use platform driver stuff, and does not have its
own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it
is really necessary on that platform, though.
Signed-off-by: Aleks Gorelov <dared1st@yahoo.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-08-09 08:24:08 +08:00
|
|
|
/* shutdown HCD */
|
|
|
|
void (*shutdown) (struct usb_hcd *hcd);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* return current frame number */
|
|
|
|
int (*get_frame_number) (struct usb_hcd *hcd);
|
|
|
|
|
|
|
|
/* manage i/o requests, device state */
|
2007-08-08 23:48:02 +08:00
|
|
|
int (*urb_enqueue)(struct usb_hcd *hcd,
|
|
|
|
struct urb *urb, gfp_t mem_flags);
|
|
|
|
int (*urb_dequeue)(struct usb_hcd *hcd,
|
|
|
|
struct urb *urb, int status);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* hw synch, freeing endpoint resources that urb_dequeue can't */
|
2010-05-18 01:58:12 +08:00
|
|
|
void (*endpoint_disable)(struct usb_hcd *hcd,
|
2005-04-17 06:20:36 +08:00
|
|
|
struct usb_host_endpoint *ep);
|
|
|
|
|
2009-04-09 01:36:28 +08:00
|
|
|
/* (optional) reset any endpoint state such as sequence number
|
|
|
|
and current window */
|
2010-05-18 01:58:12 +08:00
|
|
|
void (*endpoint_reset)(struct usb_hcd *hcd,
|
2009-04-09 01:36:28 +08:00
|
|
|
struct usb_host_endpoint *ep);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* root hub support */
|
2008-01-31 07:21:33 +08:00
|
|
|
int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
|
|
|
|
int (*hub_control) (struct usb_hcd *hcd,
|
2005-04-17 06:20:36 +08:00
|
|
|
u16 typeReq, u16 wValue, u16 wIndex,
|
|
|
|
char *buf, u16 wLength);
|
2008-01-31 07:21:33 +08:00
|
|
|
int (*bus_suspend)(struct usb_hcd *);
|
|
|
|
int (*bus_resume)(struct usb_hcd *);
|
|
|
|
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
|
2007-11-22 04:28:14 +08:00
|
|
|
|
|
|
|
/* force handover of high-speed port to full-speed companion */
|
2008-01-31 07:21:33 +08:00
|
|
|
void (*relinquish_port)(struct usb_hcd *, int);
|
2008-05-21 04:58:29 +08:00
|
|
|
/* has a port been handed over to a companion? */
|
|
|
|
int (*port_handed_over)(struct usb_hcd *, int);
|
2009-04-28 10:57:26 +08:00
|
|
|
|
2009-06-29 22:43:32 +08:00
|
|
|
/* CLEAR_TT_BUFFER completion callback */
|
|
|
|
void (*clear_tt_buffer_complete)(struct usb_hcd *,
|
|
|
|
struct usb_host_endpoint *);
|
|
|
|
|
2009-04-28 10:57:26 +08:00
|
|
|
/* xHCI specific functions */
|
|
|
|
/* Called by usb_alloc_dev to alloc HC device structures */
|
|
|
|
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
|
2010-01-10 17:15:03 +08:00
|
|
|
/* Called by usb_disconnect to free HC device structures */
|
2009-04-28 10:57:26 +08:00
|
|
|
void (*free_dev)(struct usb_hcd *, struct usb_device *);
|
2010-04-06 01:55:58 +08:00
|
|
|
/* Change a group of bulk endpoints to support multiple stream IDs */
|
|
|
|
int (*alloc_streams)(struct usb_hcd *hcd, struct usb_device *udev,
|
|
|
|
struct usb_host_endpoint **eps, unsigned int num_eps,
|
|
|
|
unsigned int num_streams, gfp_t mem_flags);
|
|
|
|
/* Reverts a group of bulk endpoints back to not using stream IDs.
|
|
|
|
* Can fail if we run out of memory.
|
|
|
|
*/
|
|
|
|
int (*free_streams)(struct usb_hcd *hcd, struct usb_device *udev,
|
|
|
|
struct usb_host_endpoint **eps, unsigned int num_eps,
|
|
|
|
gfp_t mem_flags);
|
USB: Support for bandwidth allocation.
Originally, the USB core had no support for allocating bandwidth when a
particular configuration or alternate setting for an interface was
selected. Instead, the device driver's URB submission would fail if
there was not enough bandwidth for a periodic endpoint. Drivers could
work around this, by using the scatter-gather list API to guarantee
bandwidth.
This patch adds host controller API to allow the USB core to allocate or
deallocate bandwidth for an endpoint. Endpoints are added to or dropped
from a copy of the current schedule by calling add_endpoint() or
drop_endpoint(), and then the schedule is atomically evaluated with a
call to check_bandwidth(). This allows all the endpoints for a new
configuration or alternate setting to be added at the same time that the
endpoints from the old configuration or alt setting are dropped.
Endpoints must be added to the schedule before any URBs are submitted to
them. The HCD must be allowed to reject a new configuration or alt
setting before the control transfer is sent to the device requesting the
change. It may reject the change because there is not enough bandwidth,
not enough internal resources (such as memory on an embedded host
controller), or perhaps even for security reasons in a virtualized
environment.
If the call to check_bandwidth() fails, the USB core must call
reset_bandwidth(). This causes the schedule to be reverted back to the
state it was in just after the last successful check_bandwidth() call.
If the call succeeds, the host controller driver (and hardware) will have
changed its internal state to match the new configuration or alternate
setting. The USB core can then issue a control transfer to the device to
change the configuration or alt setting. This allows the core to test new
configurations or alternate settings before unbinding drivers bound to
interfaces in the old configuration.
WIP:
The USB core must add endpoints from all interfaces in a configuration
to the schedule, because a driver may claim that interface at any time.
A slight optimization might be to add the endpoints to the schedule once
a driver claims that interface. FIXME
This patch does not cover changing alternate settings, but it does
handle a configuration change or de-configuration. FIXME
The code for managing the schedule is currently HCD specific. A generic
scheduling algorithm could be added for host controllers without
built-in scheduling support. For now, if a host controller does not
define the check_bandwidth() function, the call to
usb_hcd_check_bandwidth() will always succeed.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-28 10:58:26 +08:00
|
|
|
|
|
|
|
/* Bandwidth computation functions */
|
|
|
|
/* Note that add_endpoint() can only be called once per endpoint before
|
|
|
|
* check_bandwidth() or reset_bandwidth() must be called.
|
|
|
|
* drop_endpoint() can only be called once per endpoint also.
|
2010-05-18 01:58:12 +08:00
|
|
|
* A call to xhci_drop_endpoint() followed by a call to
|
|
|
|
* xhci_add_endpoint() will add the endpoint to the schedule with
|
|
|
|
* possibly new parameters denoted by a different endpoint descriptor
|
|
|
|
* in usb_host_endpoint. A call to xhci_add_endpoint() followed by a
|
|
|
|
* call to xhci_drop_endpoint() is not allowed.
|
USB: Support for bandwidth allocation.
Originally, the USB core had no support for allocating bandwidth when a
particular configuration or alternate setting for an interface was
selected. Instead, the device driver's URB submission would fail if
there was not enough bandwidth for a periodic endpoint. Drivers could
work around this, by using the scatter-gather list API to guarantee
bandwidth.
This patch adds host controller API to allow the USB core to allocate or
deallocate bandwidth for an endpoint. Endpoints are added to or dropped
from a copy of the current schedule by calling add_endpoint() or
drop_endpoint(), and then the schedule is atomically evaluated with a
call to check_bandwidth(). This allows all the endpoints for a new
configuration or alternate setting to be added at the same time that the
endpoints from the old configuration or alt setting are dropped.
Endpoints must be added to the schedule before any URBs are submitted to
them. The HCD must be allowed to reject a new configuration or alt
setting before the control transfer is sent to the device requesting the
change. It may reject the change because there is not enough bandwidth,
not enough internal resources (such as memory on an embedded host
controller), or perhaps even for security reasons in a virtualized
environment.
If the call to check_bandwidth() fails, the USB core must call
reset_bandwidth(). This causes the schedule to be reverted back to the
state it was in just after the last successful check_bandwidth() call.
If the call succeeds, the host controller driver (and hardware) will have
changed its internal state to match the new configuration or alternate
setting. The USB core can then issue a control transfer to the device to
change the configuration or alt setting. This allows the core to test new
configurations or alternate settings before unbinding drivers bound to
interfaces in the old configuration.
WIP:
The USB core must add endpoints from all interfaces in a configuration
to the schedule, because a driver may claim that interface at any time.
A slight optimization might be to add the endpoints to the schedule once
a driver claims that interface. FIXME
This patch does not cover changing alternate settings, but it does
handle a configuration change or de-configuration. FIXME
The code for managing the schedule is currently HCD specific. A generic
scheduling algorithm could be added for host controllers without
built-in scheduling support. For now, if a host controller does not
define the check_bandwidth() function, the call to
usb_hcd_check_bandwidth() will always succeed.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-28 10:58:26 +08:00
|
|
|
*/
|
|
|
|
/* Allocate endpoint resources and add them to a new schedule */
|
2010-05-18 01:58:12 +08:00
|
|
|
int (*add_endpoint)(struct usb_hcd *, struct usb_device *,
|
|
|
|
struct usb_host_endpoint *);
|
USB: Support for bandwidth allocation.
Originally, the USB core had no support for allocating bandwidth when a
particular configuration or alternate setting for an interface was
selected. Instead, the device driver's URB submission would fail if
there was not enough bandwidth for a periodic endpoint. Drivers could
work around this, by using the scatter-gather list API to guarantee
bandwidth.
This patch adds host controller API to allow the USB core to allocate or
deallocate bandwidth for an endpoint. Endpoints are added to or dropped
from a copy of the current schedule by calling add_endpoint() or
drop_endpoint(), and then the schedule is atomically evaluated with a
call to check_bandwidth(). This allows all the endpoints for a new
configuration or alternate setting to be added at the same time that the
endpoints from the old configuration or alt setting are dropped.
Endpoints must be added to the schedule before any URBs are submitted to
them. The HCD must be allowed to reject a new configuration or alt
setting before the control transfer is sent to the device requesting the
change. It may reject the change because there is not enough bandwidth,
not enough internal resources (such as memory on an embedded host
controller), or perhaps even for security reasons in a virtualized
environment.
If the call to check_bandwidth() fails, the USB core must call
reset_bandwidth(). This causes the schedule to be reverted back to the
state it was in just after the last successful check_bandwidth() call.
If the call succeeds, the host controller driver (and hardware) will have
changed its internal state to match the new configuration or alternate
setting. The USB core can then issue a control transfer to the device to
change the configuration or alt setting. This allows the core to test new
configurations or alternate settings before unbinding drivers bound to
interfaces in the old configuration.
WIP:
The USB core must add endpoints from all interfaces in a configuration
to the schedule, because a driver may claim that interface at any time.
A slight optimization might be to add the endpoints to the schedule once
a driver claims that interface. FIXME
This patch does not cover changing alternate settings, but it does
handle a configuration change or de-configuration. FIXME
The code for managing the schedule is currently HCD specific. A generic
scheduling algorithm could be added for host controllers without
built-in scheduling support. For now, if a host controller does not
define the check_bandwidth() function, the call to
usb_hcd_check_bandwidth() will always succeed.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-28 10:58:26 +08:00
|
|
|
/* Drop an endpoint from a new schedule */
|
2010-05-18 01:58:12 +08:00
|
|
|
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *,
|
|
|
|
struct usb_host_endpoint *);
|
USB: Support for bandwidth allocation.
Originally, the USB core had no support for allocating bandwidth when a
particular configuration or alternate setting for an interface was
selected. Instead, the device driver's URB submission would fail if
there was not enough bandwidth for a periodic endpoint. Drivers could
work around this, by using the scatter-gather list API to guarantee
bandwidth.
This patch adds host controller API to allow the USB core to allocate or
deallocate bandwidth for an endpoint. Endpoints are added to or dropped
from a copy of the current schedule by calling add_endpoint() or
drop_endpoint(), and then the schedule is atomically evaluated with a
call to check_bandwidth(). This allows all the endpoints for a new
configuration or alternate setting to be added at the same time that the
endpoints from the old configuration or alt setting are dropped.
Endpoints must be added to the schedule before any URBs are submitted to
them. The HCD must be allowed to reject a new configuration or alt
setting before the control transfer is sent to the device requesting the
change. It may reject the change because there is not enough bandwidth,
not enough internal resources (such as memory on an embedded host
controller), or perhaps even for security reasons in a virtualized
environment.
If the call to check_bandwidth() fails, the USB core must call
reset_bandwidth(). This causes the schedule to be reverted back to the
state it was in just after the last successful check_bandwidth() call.
If the call succeeds, the host controller driver (and hardware) will have
changed its internal state to match the new configuration or alternate
setting. The USB core can then issue a control transfer to the device to
change the configuration or alt setting. This allows the core to test new
configurations or alternate settings before unbinding drivers bound to
interfaces in the old configuration.
WIP:
The USB core must add endpoints from all interfaces in a configuration
to the schedule, because a driver may claim that interface at any time.
A slight optimization might be to add the endpoints to the schedule once
a driver claims that interface. FIXME
This patch does not cover changing alternate settings, but it does
handle a configuration change or de-configuration. FIXME
The code for managing the schedule is currently HCD specific. A generic
scheduling algorithm could be added for host controllers without
built-in scheduling support. For now, if a host controller does not
define the check_bandwidth() function, the call to
usb_hcd_check_bandwidth() will always succeed.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-28 10:58:26 +08:00
|
|
|
/* Check that a new hardware configuration, set using
|
|
|
|
* endpoint_enable and endpoint_disable, does not exceed bus
|
|
|
|
* bandwidth. This must be called before any set configuration
|
|
|
|
* or set interface requests are sent to the device.
|
|
|
|
*/
|
|
|
|
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
|
|
|
|
/* Reset the device schedule to the last known good schedule,
|
|
|
|
* which was set from a previous successful call to
|
|
|
|
* check_bandwidth(). This reverts any add_endpoint() and
|
|
|
|
* drop_endpoint() calls since that last successful call.
|
|
|
|
* Used for when a check_bandwidth() call fails due to resource
|
|
|
|
* or bandwidth constraints.
|
|
|
|
*/
|
|
|
|
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
2009-04-28 10:57:26 +08:00
|
|
|
/* Returns the hardware-chosen device address */
|
|
|
|
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
|
2009-09-05 01:53:24 +08:00
|
|
|
/* Notifies the HCD after a hub descriptor is fetched.
|
|
|
|
* Will block.
|
|
|
|
*/
|
|
|
|
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
|
|
|
|
struct usb_tt *tt, gfp_t mem_flags);
|
2009-12-10 07:59:17 +08:00
|
|
|
int (*reset_device)(struct usb_hcd *, struct usb_device *);
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2007-08-08 23:48:02 +08:00
|
|
|
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
|
|
|
|
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
|
|
|
|
int status);
|
|
|
|
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
|
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
|
|
|
|
extern int usb_hcd_unlink_urb(struct urb *urb, int status);
|
2007-08-25 03:42:24 +08:00
|
|
|
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
|
|
|
|
int status);
|
2007-09-10 23:33:05 +08:00
|
|
|
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
|
|
|
|
struct usb_host_endpoint *ep);
|
|
|
|
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
|
2006-08-30 23:27:36 +08:00
|
|
|
struct usb_host_endpoint *ep);
|
2009-04-09 01:36:28 +08:00
|
|
|
extern void usb_hcd_reset_endpoint(struct usb_device *udev,
|
|
|
|
struct usb_host_endpoint *ep);
|
2008-10-22 03:28:46 +08:00
|
|
|
extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
|
USB: Check bandwidth when switching alt settings.
Make the USB core check the bandwidth when switching from one
interface alternate setting to another. Also check the bandwidth
when resetting a configuration (so that alt setting 0 is used). If
this check fails, the device's state is unchanged. If the device
refuses the new alt setting, re-instate the old alt setting in the
host controller hardware.
If a USB device doesn't have an alternate interface setting 0, install
the first alt setting in its descriptors when a new configuration is
requested, or the device is reset.
Add a mutex per root hub to protect bandwidth operations:
adding/reseting/changing configurations, and changing alternate interface
settings. We want to ensure that the xHCI host controller and the USB
device are set up for the same configurations and alternate settings.
There are two (possibly three) steps to do this:
1. The host controller needs to check that bandwidth is available for a
different setting, by issuing and waiting for a configure endpoint
command.
2. Once that returns successfully, a control message is sent to the
device.
3. If that fails, the host controller must be notified through another
configure endpoint command.
The mutex is used to make these three operations seem atomic, to prevent
another driver from using more bandwidth for a different device while
we're in the middle of these operations.
While we're touching the bandwidth code, rename usb_hcd_check_bandwidth()
to usb_hcd_alloc_bandwidth(). This function does more than just check
that the bandwidth change won't exceed the bus bandwidth; it actually
changes the bandwidth configuration in the xHCI host controller.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-12-04 01:44:36 +08:00
|
|
|
extern int usb_hcd_alloc_bandwidth(struct usb_device *udev,
|
USB: Support for bandwidth allocation.
Originally, the USB core had no support for allocating bandwidth when a
particular configuration or alternate setting for an interface was
selected. Instead, the device driver's URB submission would fail if
there was not enough bandwidth for a periodic endpoint. Drivers could
work around this, by using the scatter-gather list API to guarantee
bandwidth.
This patch adds host controller API to allow the USB core to allocate or
deallocate bandwidth for an endpoint. Endpoints are added to or dropped
from a copy of the current schedule by calling add_endpoint() or
drop_endpoint(), and then the schedule is atomically evaluated with a
call to check_bandwidth(). This allows all the endpoints for a new
configuration or alternate setting to be added at the same time that the
endpoints from the old configuration or alt setting are dropped.
Endpoints must be added to the schedule before any URBs are submitted to
them. The HCD must be allowed to reject a new configuration or alt
setting before the control transfer is sent to the device requesting the
change. It may reject the change because there is not enough bandwidth,
not enough internal resources (such as memory on an embedded host
controller), or perhaps even for security reasons in a virtualized
environment.
If the call to check_bandwidth() fails, the USB core must call
reset_bandwidth(). This causes the schedule to be reverted back to the
state it was in just after the last successful check_bandwidth() call.
If the call succeeds, the host controller driver (and hardware) will have
changed its internal state to match the new configuration or alternate
setting. The USB core can then issue a control transfer to the device to
change the configuration or alt setting. This allows the core to test new
configurations or alternate settings before unbinding drivers bound to
interfaces in the old configuration.
WIP:
The USB core must add endpoints from all interfaces in a configuration
to the schedule, because a driver may claim that interface at any time.
A slight optimization might be to add the endpoints to the schedule once
a driver claims that interface. FIXME
This patch does not cover changing alternate settings, but it does
handle a configuration change or de-configuration. FIXME
The code for managing the schedule is currently HCD specific. A generic
scheduling algorithm could be added for host controllers without
built-in scheduling support. For now, if a host controller does not
define the check_bandwidth() function, the call to
usb_hcd_check_bandwidth() will always succeed.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-28 10:58:26 +08:00
|
|
|
struct usb_host_config *new_config,
|
USB: Check bandwidth when switching alt settings.
Make the USB core check the bandwidth when switching from one
interface alternate setting to another. Also check the bandwidth
when resetting a configuration (so that alt setting 0 is used). If
this check fails, the device's state is unchanged. If the device
refuses the new alt setting, re-instate the old alt setting in the
host controller hardware.
If a USB device doesn't have an alternate interface setting 0, install
the first alt setting in its descriptors when a new configuration is
requested, or the device is reset.
Add a mutex per root hub to protect bandwidth operations:
adding/reseting/changing configurations, and changing alternate interface
settings. We want to ensure that the xHCI host controller and the USB
device are set up for the same configurations and alternate settings.
There are two (possibly three) steps to do this:
1. The host controller needs to check that bandwidth is available for a
different setting, by issuing and waiting for a configure endpoint
command.
2. Once that returns successfully, a control message is sent to the
device.
3. If that fails, the host controller must be notified through another
configure endpoint command.
The mutex is used to make these three operations seem atomic, to prevent
another driver from using more bandwidth for a different device while
we're in the middle of these operations.
While we're touching the bandwidth code, rename usb_hcd_check_bandwidth()
to usb_hcd_alloc_bandwidth(). This function does more than just check
that the bandwidth change won't exceed the bus bandwidth; it actually
changes the bandwidth configuration in the xHCI host controller.
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2009-12-04 01:44:36 +08:00
|
|
|
struct usb_host_interface *old_alt,
|
|
|
|
struct usb_host_interface *new_alt);
|
2008-01-31 07:21:33 +08:00
|
|
|
extern int usb_hcd_get_frame_number(struct usb_device *udev);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
2008-07-03 03:46:22 +08:00
|
|
|
struct device *dev, const char *bus_name);
|
2008-01-31 07:21:33 +08:00
|
|
|
extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
|
|
|
|
extern void usb_put_hcd(struct usb_hcd *hcd);
|
2005-04-17 06:20:36 +08:00
|
|
|
extern int usb_add_hcd(struct usb_hcd *hcd,
|
|
|
|
unsigned int irqnum, unsigned long irqflags);
|
|
|
|
extern void usb_remove_hcd(struct usb_hcd *hcd);
|
|
|
|
|
USB: Properly unregister reboot notifier in case of failure in ehci hcd
If some problem occurs during ehci startup, for instance, request_irq fails,
echi hcd driver tries it best to cleanup, but fails to unregister reboot
notifier, which in turn leads to crash on reboot/poweroff.
The following patch resolves this problem by not using reboot notifiers
anymore, but instead making ehci/ohci driver get its own shutdown method. For
PCI, it is done through pci glue, for everything else through platform driver
glue.
One downside: sa1111 does not use platform driver stuff, and does not have its
own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it
is really necessary on that platform, though.
Signed-off-by: Aleks Gorelov <dared1st@yahoo.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-08-09 08:24:08 +08:00
|
|
|
struct platform_device;
|
2008-01-31 07:21:33 +08:00
|
|
|
extern void usb_hcd_platform_shutdown(struct platform_device *dev);
|
USB: Properly unregister reboot notifier in case of failure in ehci hcd
If some problem occurs during ehci startup, for instance, request_irq fails,
echi hcd driver tries it best to cleanup, but fails to unregister reboot
notifier, which in turn leads to crash on reboot/poweroff.
The following patch resolves this problem by not using reboot notifiers
anymore, but instead making ehci/ohci driver get its own shutdown method. For
PCI, it is done through pci glue, for everything else through platform driver
glue.
One downside: sa1111 does not use platform driver stuff, and does not have its
own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it
is really necessary on that platform, though.
Signed-off-by: Aleks Gorelov <dared1st@yahoo.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-08-09 08:24:08 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
struct pci_dev;
|
|
|
|
struct pci_device_id;
|
2008-01-31 07:21:33 +08:00
|
|
|
extern int usb_hcd_pci_probe(struct pci_dev *dev,
|
2005-04-17 06:20:36 +08:00
|
|
|
const struct pci_device_id *id);
|
2008-01-31 07:21:33 +08:00
|
|
|
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
|
|
|
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
USB: Properly unregister reboot notifier in case of failure in ehci hcd
If some problem occurs during ehci startup, for instance, request_irq fails,
echi hcd driver tries it best to cleanup, but fails to unregister reboot
notifier, which in turn leads to crash on reboot/poweroff.
The following patch resolves this problem by not using reboot notifiers
anymore, but instead making ehci/ohci driver get its own shutdown method. For
PCI, it is done through pci glue, for everything else through platform driver
glue.
One downside: sa1111 does not use platform driver stuff, and does not have its
own shutdown hook, so no 'shutdown' is called for it now. I'm not sure if it
is really necessary on that platform, though.
Signed-off-by: Aleks Gorelov <dared1st@yahoo.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-08-09 08:24:08 +08:00
|
|
|
|
2009-04-28 01:33:24 +08:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2009-12-15 10:00:08 +08:00
|
|
|
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
|
2009-04-28 01:33:24 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif /* CONFIG_PCI */
|
|
|
|
|
|
|
|
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
|
2008-01-31 07:21:33 +08:00
|
|
|
int hcd_buffer_create(struct usb_hcd *hcd);
|
|
|
|
void hcd_buffer_destroy(struct usb_hcd *hcd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
|
2005-10-21 15:21:58 +08:00
|
|
|
gfp_t mem_flags, dma_addr_t *dma);
|
2008-01-31 07:21:33 +08:00
|
|
|
void hcd_buffer_free(struct usb_bus *bus, size_t size,
|
2005-04-17 06:20:36 +08:00
|
|
|
void *addr, dma_addr_t dma);
|
|
|
|
|
|
|
|
/* generic bus glue, needed for host controllers that don't use PCI */
|
2008-01-31 07:21:33 +08:00
|
|
|
extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
|
2005-04-22 03:56:37 +08:00
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
extern void usb_hc_died(struct usb_hcd *hcd);
|
2005-04-22 03:56:37 +08:00
|
|
|
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-04-09 01:36:28 +08:00
|
|
|
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
|
|
|
|
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
|
|
|
|
#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))
|
|
|
|
#define usb_settoggle(dev, ep, out, bit) \
|
|
|
|
((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \
|
|
|
|
((bit) << (ep)))
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/* Enumeration is only for the hub driver, or HCD virtual root hubs */
|
|
|
|
extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|
|
|
struct usb_bus *, unsigned port);
|
|
|
|
extern int usb_new_device(struct usb_device *dev);
|
|
|
|
extern void usb_disconnect(struct usb_device **);
|
|
|
|
|
|
|
|
extern int usb_get_configuration(struct usb_device *dev);
|
|
|
|
extern void usb_destroy_configuration(struct usb_device *dev);
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* HCD Root Hub support
|
|
|
|
*/
|
|
|
|
|
2010-04-25 05:38:17 +08:00
|
|
|
#include <linux/usb/ch11.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As of USB 2.0, full/low speed devices are segregated into trees.
|
|
|
|
* One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
|
|
|
|
* The other type grows from high speed hubs when they connect to
|
|
|
|
* full/low speed devices using "Transaction Translators" (TTs).
|
|
|
|
*
|
|
|
|
* TTs should only be known to the hub driver, and high speed bus
|
|
|
|
* drivers (only EHCI for now). They affect periodic scheduling and
|
|
|
|
* sometimes control/bulk error recovery.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct usb_device;
|
|
|
|
|
|
|
|
struct usb_tt {
|
|
|
|
struct usb_device *hub; /* upstream highspeed hub */
|
|
|
|
int multi; /* true means one TT per port */
|
|
|
|
unsigned think_time; /* think time in ns */
|
|
|
|
|
|
|
|
/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
|
|
|
|
spinlock_t lock;
|
|
|
|
struct list_head clear_list; /* of usb_tt_clear */
|
|
|
|
struct work_struct clear_work;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct usb_tt_clear {
|
|
|
|
struct list_head clear_list;
|
|
|
|
unsigned tt;
|
|
|
|
u16 devinfo;
|
|
|
|
struct usb_hcd *hcd;
|
|
|
|
struct usb_host_endpoint *ep;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern int usb_hub_clear_tt_buffer(struct urb *urb);
|
|
|
|
extern void usb_ep0_reinit(struct usb_device *);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
|
|
|
|
#define DeviceRequest \
|
|
|
|
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
|
|
|
#define DeviceOutRequest \
|
|
|
|
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
|
|
|
|
|
|
|
|
#define InterfaceRequest \
|
|
|
|
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
|
|
|
|
|
|
|
#define EndpointRequest \
|
|
|
|
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
|
|
|
#define EndpointOutRequest \
|
|
|
|
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
|
|
|
|
|
|
|
|
/* class requests from the USB 2.0 hub spec, table 11-15 */
|
|
|
|
/* GetBusState and SetHubDescriptor are optional, omitted */
|
|
|
|
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
|
|
|
|
#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
|
|
|
|
#define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR)
|
|
|
|
#define GetHubStatus (0xa000 | USB_REQ_GET_STATUS)
|
|
|
|
#define GetPortStatus (0xa300 | USB_REQ_GET_STATUS)
|
|
|
|
#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
|
|
|
|
#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic bandwidth allocation constants/support
|
|
|
|
*/
|
|
|
|
#define FRAME_TIME_USECS 1000L
|
2008-01-31 07:21:33 +08:00
|
|
|
#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Trying not to use worst-case bit-stuffing
|
2008-01-31 07:21:33 +08:00
|
|
|
* of (7/6 * 8 * bytecount) = 9.33 * bytecount */
|
2005-04-17 06:20:36 +08:00
|
|
|
/* bytecount = data payload byte count */
|
|
|
|
|
|
|
|
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
|
|
|
|
/* convert & round nanoseconds to microseconds */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Full/low speed bandwidth allocation constants/support.
|
|
|
|
*/
|
|
|
|
#define BW_HOST_DELAY 1000L /* nanoseconds */
|
|
|
|
#define BW_HUB_LS_SETUP 333L /* nanoseconds */
|
2008-01-31 07:21:33 +08:00
|
|
|
/* 4 full-speed bit times (est.) */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
#define FRAME_TIME_BITS 12000L /* frame = 1 millisecond */
|
2005-04-17 06:20:36 +08:00
|
|
|
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
|
|
|
|
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
|
|
|
|
|
|
|
|
/*
|
2005-07-30 03:18:28 +08:00
|
|
|
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
|
2005-04-17 06:20:36 +08:00
|
|
|
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
|
|
|
|
* to preallocate bandwidth)
|
|
|
|
*/
|
|
|
|
#define USB2_HOST_DELAY 5 /* nsec, guess */
|
2008-01-31 07:21:33 +08:00
|
|
|
#define HS_NSECS(bytes) (((55 * 8 * 2083) \
|
2005-08-12 10:37:01 +08:00
|
|
|
+ (2083UL * (3 + BitTime(bytes))))/1000 \
|
2005-04-17 06:20:36 +08:00
|
|
|
+ USB2_HOST_DELAY)
|
2008-01-31 07:21:33 +08:00
|
|
|
#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
|
2005-08-12 10:37:01 +08:00
|
|
|
+ (2083UL * (3 + BitTime(bytes))))/1000 \
|
2005-04-17 06:20:36 +08:00
|
|
|
+ USB2_HOST_DELAY)
|
2010-05-18 01:58:12 +08:00
|
|
|
#define HS_USECS(bytes) NS_TO_US(HS_NSECS(bytes))
|
|
|
|
#define HS_USECS_ISO(bytes) NS_TO_US(HS_NSECS_ISO(bytes))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
extern long usb_calc_bus_time(int speed, int is_input,
|
2005-04-17 06:20:36 +08:00
|
|
|
int isoc, int bytecount);
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
extern void usb_set_device_state(struct usb_device *udev,
|
|
|
|
enum usb_device_state new_state);
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* exported only within usbcore */
|
|
|
|
|
|
|
|
extern struct list_head usb_bus_list;
|
2006-01-11 22:55:29 +08:00
|
|
|
extern struct mutex usb_bus_list_lock;
|
2005-04-17 06:20:36 +08:00
|
|
|
extern wait_queue_head_t usb_kill_urb_queue;
|
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
extern int usb_find_interface_driver(struct usb_device *dev,
|
2005-04-17 06:20:36 +08:00
|
|
|
struct usb_interface *interface);
|
|
|
|
|
|
|
|
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
|
|
|
|
|
2005-10-14 05:08:02 +08:00
|
|
|
#ifdef CONFIG_PM
|
2008-01-31 07:21:33 +08:00
|
|
|
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
|
2008-11-26 05:39:18 +08:00
|
|
|
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
|
|
|
|
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
|
2010-01-09 01:57:28 +08:00
|
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
|
|
|
#ifdef CONFIG_USB_SUSPEND
|
|
|
|
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
|
2005-10-14 05:08:02 +08:00
|
|
|
#else
|
2005-10-24 14:04:25 +08:00
|
|
|
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2010-01-09 01:57:28 +08:00
|
|
|
#endif /* CONFIG_USB_SUSPEND */
|
|
|
|
|
2005-10-14 05:08:02 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* USB device fs stuff
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef CONFIG_USB_DEVICEFS
|
|
|
|
|
|
|
|
/*
|
|
|
|
* these are expected to be called from the USB core/hub thread
|
|
|
|
* with the kernel lock held
|
|
|
|
*/
|
2008-01-31 07:21:33 +08:00
|
|
|
extern void usbfs_update_special(void);
|
2005-04-17 06:20:36 +08:00
|
|
|
extern int usbfs_init(void);
|
|
|
|
extern void usbfs_cleanup(void);
|
|
|
|
|
|
|
|
#else /* CONFIG_USB_DEVICEFS */
|
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
static inline void usbfs_update_special(void) {}
|
2005-04-17 06:20:36 +08:00
|
|
|
static inline int usbfs_init(void) { return 0; }
|
|
|
|
static inline void usbfs_cleanup(void) { }
|
|
|
|
|
|
|
|
#endif /* CONFIG_USB_DEVICEFS */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
2008-11-14 12:31:21 +08:00
|
|
|
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
struct usb_mon_operations {
|
|
|
|
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
|
|
|
|
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
|
2007-08-25 03:41:41 +08:00
|
|
|
void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
|
2005-04-17 06:20:36 +08:00
|
|
|
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
|
|
|
|
};
|
|
|
|
|
|
|
|
extern struct usb_mon_operations *mon_ops;
|
|
|
|
|
|
|
|
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb)
|
|
|
|
{
|
|
|
|
if (bus->monitored)
|
|
|
|
(*mon_ops->urb_submit)(bus, urb);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
|
|
|
|
int error)
|
|
|
|
{
|
|
|
|
if (bus->monitored)
|
|
|
|
(*mon_ops->urb_submit_error)(bus, urb, error);
|
|
|
|
}
|
|
|
|
|
2007-08-25 03:41:41 +08:00
|
|
|
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
|
|
|
|
int status)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (bus->monitored)
|
2007-08-25 03:41:41 +08:00
|
|
|
(*mon_ops->urb_complete)(bus, urb, status);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int usb_mon_register(struct usb_mon_operations *ops);
|
|
|
|
void usb_mon_deregister(void);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
|
|
|
|
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
|
|
|
|
int error) {}
|
2007-08-25 03:41:41 +08:00
|
|
|
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
|
|
|
|
int status) {}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-14 12:31:21 +08:00
|
|
|
#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
|
2008-01-31 07:21:33 +08:00
|
|
|
/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
|
2010-05-18 01:58:12 +08:00
|
|
|
#define bitmap DeviceRemovable
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* random stuff */
|
|
|
|
|
2008-01-31 07:21:33 +08:00
|
|
|
#define RUN_CONTEXT (in_irq() ? "in_irq" \
|
|
|
|
: (in_interrupt() ? "in_interrupt" : "can sleep"))
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
|
2007-10-11 04:27:07 +08:00
|
|
|
/* This rwsem is for use only by the hub driver and ehci-hcd.
|
|
|
|
* Nobody else should touch it.
|
|
|
|
*/
|
|
|
|
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-10-02 23:48:13 +08:00
|
|
|
/* Keep track of which host controller drivers are loaded */
|
|
|
|
#define USB_UHCI_LOADED 0
|
|
|
|
#define USB_OHCI_LOADED 1
|
|
|
|
#define USB_EHCI_LOADED 2
|
|
|
|
extern unsigned long usb_hcds_loaded;
|
|
|
|
|
2007-10-11 04:27:07 +08:00
|
|
|
#endif /* __KERNEL__ */
|
2008-10-30 05:25:50 +08:00
|
|
|
|
|
|
|
#endif /* __USB_CORE_HCD_H */
|