Commit 1f419cad authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

parents 974f7bc5 4303fc6f
...@@ -291,7 +291,7 @@ ...@@ -291,7 +291,7 @@
!Edrivers/usb/core/hcd.c !Edrivers/usb/core/hcd.c
!Edrivers/usb/core/hcd-pci.c !Edrivers/usb/core/hcd-pci.c
!Edrivers/usb/core/buffer.c !Idrivers/usb/core/buffer.c
</chapter> </chapter>
<chapter> <chapter>
......
...@@ -2,7 +2,6 @@ Driver documentation for yealink usb-p1k phones ...@@ -2,7 +2,6 @@ Driver documentation for yealink usb-p1k phones
0. Status 0. Status
~~~~~~~~~ ~~~~~~~~~
The p1k is a relatively cheap usb 1.1 phone with: The p1k is a relatively cheap usb 1.1 phone with:
- keyboard full support, yealink.ko / input event API - keyboard full support, yealink.ko / input event API
- LCD full support, yealink.ko / sysfs API - LCD full support, yealink.ko / sysfs API
...@@ -17,9 +16,8 @@ For vendor documentation see http://www.yealink.com ...@@ -17,9 +16,8 @@ For vendor documentation see http://www.yealink.com
1. Compilation (stand alone version) 1. Compilation (stand alone version)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently only kernel 2.6.x.y versions are supported. Currently only kernel 2.6.x.y versions are supported.
In order to build the yealink.ko module do: In order to build the yealink.ko module do
make make
...@@ -28,6 +26,21 @@ the Makefile is pointing to the location where your kernel sources ...@@ -28,6 +26,21 @@ the Makefile is pointing to the location where your kernel sources
are located, default /usr/src/linux. are located, default /usr/src/linux.
1.1 Troubleshooting
~~~~~~~~~~~~~~~~~~~
Q: Module yealink compiled and installed without any problem but phone
is not initialized and does not react to any actions.
A: If you see something like:
hiddev0: USB HID v1.00 Device [Yealink Network Technology Ltd. VOIP USB Phone
in dmesg, it means that the hid driver has grabbed the device first. Try to
load module yealink before any other usb hid driver. Please see the
instructions provided by your distribution on module configuration.
Q: Phone is working now (displays version and accepts keypad input) but I can't
find the sysfs files.
A: The sysfs files are located on the particular usb endpoint. On most
distributions you can do: "find /sys/ -name get_icons" for a hint.
2. keyboard features 2. keyboard features
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
......
...@@ -1517,8 +1517,6 @@ running once the system is up. ...@@ -1517,8 +1517,6 @@ running once the system is up.
uart6850= [HW,OSS] uart6850= [HW,OSS]
Format: <io>,<irq> Format: <io>,<irq>
usb-handoff [HW] Enable early USB BIOS -> OS handoff
usbhid.mousepoll= usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at. [USBHID] The interval which mice are to be polled at.
......
...@@ -116,12 +116,6 @@ M: ajk@iehk.rwth-aachen.de ...@@ -116,12 +116,6 @@ M: ajk@iehk.rwth-aachen.de
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
YEALINK PHONE DRIVER
P: Henk Vergonet
M: Henk.Vergonet@gmail.com
L: usbb2k-api-dev@nongnu.org
S: Maintained
8139CP 10/100 FAST ETHERNET DRIVER 8139CP 10/100 FAST ETHERNET DRIVER
P: Jeff Garzik P: Jeff Garzik
M: jgarzik@pobox.com M: jgarzik@pobox.com
...@@ -2495,14 +2489,6 @@ L: linux-kernel@vger.kernel.org ...@@ -2495,14 +2489,6 @@ L: linux-kernel@vger.kernel.org
L: linux-usb-devel@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net
S: Supported S: Supported
USB BLUETOOTH TTY CONVERTER DRIVER
P: Greg Kroah-Hartman
M: greg@kroah.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
W: http://www.kroah.com/linux-usb/
USB CDC ETHERNET DRIVER USB CDC ETHERNET DRIVER
P: Greg Kroah-Hartman P: Greg Kroah-Hartman
M: greg@kroah.com M: greg@kroah.com
...@@ -2863,6 +2849,12 @@ M: jpr@f6fbb.org ...@@ -2863,6 +2849,12 @@ M: jpr@f6fbb.org
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
YEALINK PHONE DRIVER
P: Henk Vergonet
M: Henk.Vergonet@gmail.com
L: usbb2k-api-dev@nongnu.org
S: Maintained
YMFPCI YAMAHA PCI SOUND (Use ALSA instead) YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
P: Pete Zaitcev P: Pete Zaitcev
M: zaitcev@yahoo.com M: zaitcev@yahoo.com
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# Rewritten to use lists instead of if-statements. # Rewritten to use lists instead of if-statements.
# #
obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PCI) += pci/ usb/
obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_PARISC) += parisc/
obj-y += video/ obj-y += video/
obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_ACPI) += acpi/
......
...@@ -30,23 +30,6 @@ LIST_HEAD(dpm_off_irq); ...@@ -30,23 +30,6 @@ LIST_HEAD(dpm_off_irq);
DECLARE_MUTEX(dpm_sem); DECLARE_MUTEX(dpm_sem);
DECLARE_MUTEX(dpm_list_sem); DECLARE_MUTEX(dpm_list_sem);
/*
* PM Reference Counting.
*/
static inline void device_pm_hold(struct device * dev)
{
if (dev)
atomic_inc(&dev->power.pm_users);
}
static inline void device_pm_release(struct device * dev)
{
if (dev)
atomic_dec(&dev->power.pm_users);
}
/** /**
* device_pm_set_parent - Specify power dependency. * device_pm_set_parent - Specify power dependency.
* @dev: Device who needs power. * @dev: Device who needs power.
...@@ -62,10 +45,8 @@ static inline void device_pm_release(struct device * dev) ...@@ -62,10 +45,8 @@ static inline void device_pm_release(struct device * dev)
void device_pm_set_parent(struct device * dev, struct device * parent) void device_pm_set_parent(struct device * dev, struct device * parent)
{ {
struct device * old_parent = dev->power.pm_parent; put_device(dev->power.pm_parent);
device_pm_release(old_parent); dev->power.pm_parent = get_device(parent);
dev->power.pm_parent = parent;
device_pm_hold(parent);
} }
EXPORT_SYMBOL_GPL(device_pm_set_parent); EXPORT_SYMBOL_GPL(device_pm_set_parent);
...@@ -75,7 +56,6 @@ int device_pm_add(struct device * dev) ...@@ -75,7 +56,6 @@ int device_pm_add(struct device * dev)
pr_debug("PM: Adding info for %s:%s\n", pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
atomic_set(&dev->power.pm_users, 0);
down(&dpm_list_sem); down(&dpm_list_sem);
list_add_tail(&dev->power.entry, &dpm_active); list_add_tail(&dev->power.entry, &dpm_active);
device_pm_set_parent(dev, dev->parent); device_pm_set_parent(dev, dev->parent);
...@@ -91,7 +71,7 @@ void device_pm_remove(struct device * dev) ...@@ -91,7 +71,7 @@ void device_pm_remove(struct device * dev)
dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
down(&dpm_list_sem); down(&dpm_list_sem);
dpm_sysfs_remove(dev); dpm_sysfs_remove(dev);
device_pm_release(dev->power.pm_parent); put_device(dev->power.pm_parent);
list_del_init(&dev->power.entry); list_del_init(&dev->power.entry);
up(&dpm_list_sem); up(&dpm_list_sem);
} }
......
...@@ -67,9 +67,6 @@ extern int suspend_device(struct device *, pm_message_t); ...@@ -67,9 +67,6 @@ extern int suspend_device(struct device *, pm_message_t);
* runtime.c * runtime.c
*/ */
extern int dpm_runtime_suspend(struct device *, pm_message_t);
extern void dpm_runtime_resume(struct device *);
#else /* CONFIG_PM */ #else /* CONFIG_PM */
...@@ -82,14 +79,4 @@ static inline void device_pm_remove(struct device * dev) ...@@ -82,14 +79,4 @@ static inline void device_pm_remove(struct device * dev)
} }
static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
{
return 0;
}
static inline void dpm_runtime_resume(struct device * dev)
{
}
#endif #endif
...@@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev) ...@@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev)
runtime_resume(dev); runtime_resume(dev);
up(&dpm_sem); up(&dpm_sem);
} }
EXPORT_SYMBOL(dpm_runtime_resume);
/** /**
......
...@@ -1512,7 +1512,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -1512,7 +1512,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scmd->nsg = 1; scmd->nsg = 1;
sg = &scmd->sgv[0]; sg = &scmd->sgv[0];
sg->page = virt_to_page(sc->top_sense); sg->page = virt_to_page(sc->top_sense);
sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1); sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1);
sg->length = UB_SENSE_SIZE; sg->length = UB_SENSE_SIZE;
scmd->len = UB_SENSE_SIZE; scmd->len = UB_SENSE_SIZE;
scmd->lun = cmd->lun; scmd->lun = cmd->lun;
...@@ -1891,7 +1891,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, ...@@ -1891,7 +1891,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
cmd->nsg = 1; cmd->nsg = 1;
sg = &cmd->sgv[0]; sg = &cmd->sgv[0];
sg->page = virt_to_page(p); sg->page = virt_to_page(p);
sg->offset = (unsigned int)p & (PAGE_SIZE-1); sg->offset = (unsigned long)p & (PAGE_SIZE-1);
sg->length = 8; sg->length = 8;
cmd->len = 8; cmd->len = 8;
cmd->lun = lun; cmd->lun = lun;
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* *
* Copyright (c) 1999 Martin Mares <mj@ucw.cz> * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
* *
* Init/reset quirks for USB host controllers should be in the
* USB quirks file, where their drivers can access reuse it.
*
* The bridge optimization stuff has been removed. If you really * The bridge optimization stuff has been removed. If you really
* have a silly BIOS which is unable to set your host bridge right, * have a silly BIOS which is unable to set your host bridge right,
* use the PowerTweak utility (see http://powertweak.sourceforge.net). * use the PowerTweak utility (see http://powertweak.sourceforge.net).
...@@ -644,28 +647,6 @@ static void quirk_via_irq(struct pci_dev *dev) ...@@ -644,28 +647,6 @@ static void quirk_via_irq(struct pci_dev *dev)
} }
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
/*
* PIIX3 USB: We have to disable USB interrupts that are
* hardwired to PIRQD# and may be shared with an
* external device.
*
* Legacy Support Register (LEGSUP):
* bit13: USB PIRQ Enable (USBPIRQDEN),
* bit4: Trap/SMI On IRQ Enable (USBSMIEN).
*
* We mask out all r/wc bits, too.
*/
static void __devinit quirk_piix3_usb(struct pci_dev *dev)
{
u16 legsup;
pci_read_config_word(dev, 0xc0, &legsup);
legsup &= 0x50ef;
pci_write_config_word(dev, 0xc0, legsup);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb );
/* /*
* VIA VT82C598 has its device ID settable and many BIOSes * VIA VT82C598 has its device ID settable and many BIOSes
* set it to the ID of VT82C597 for backward compatibility. * set it to the ID of VT82C597 for backward compatibility.
...@@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev) ...@@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
pci_read_config_byte(dev, 0x77, &val); pci_read_config_byte(dev, 0x77, &val);
} }
#define UHCI_USBLEGSUP 0xc0 /* legacy support */
#define UHCI_USBCMD 0 /* command register */
#define UHCI_USBSTS 2 /* status register */
#define UHCI_USBINTR 4 /* interrupt register */
#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
#define OHCI_CONTROL 0x04
#define OHCI_CMDSTATUS 0x08
#define OHCI_INTRSTATUS 0x0c
#define OHCI_INTRENABLE 0x10
#define OHCI_INTRDISABLE 0x14
#define OHCI_OCR (1 << 3) /* ownership change request */
#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
#define OHCI_INTR_OC (1 << 30) /* ownership change */
#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
#define EHCI_USBCMD 0 /* command register */
#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
#define EHCI_USBSTS 4 /* status register */
#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
#define EHCI_USBINTR 8 /* interrupt register */
#define EHCI_USBLEGSUP 0 /* legacy support register */
#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
int usb_early_handoff __devinitdata = 0;
static int __init usb_handoff_early(char *str)
{
usb_early_handoff = 1;
return 0;
}
__setup("usb-handoff", usb_handoff_early);
static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
{
unsigned long base = 0;
int wait_time, delta;
u16 val, sts;
int i;
for (i = 0; i < PCI_ROM_RESOURCE; i++)
if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
base = pci_resource_start(pdev, i);
break;
}
if (!base)
return;
/*
* stop controller
*/
sts = inw(base + UHCI_USBSTS);
val = inw(base + UHCI_USBCMD);
val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
outw(val, base + UHCI_USBCMD);
/*
* wait while it stops if it was running
*/
if ((sts & UHCI_USBSTS_HALTED) == 0)
{
wait_time = 1000;
delta = 100;
do {
outw(0x1f, base + UHCI_USBSTS);
udelay(delta);
wait_time -= delta;
val = inw(base + UHCI_USBSTS);
if (val & UHCI_USBSTS_HALTED)
break;
} while (wait_time > 0);
}
/*
* disable interrupts & legacy support
*/
outw(0, base + UHCI_USBINTR);
outw(0x1f, base + UHCI_USBSTS);
pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
if (val & 0xbf)
pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
}
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
int wait_time;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL) return;
if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
wait_time = 500; /* 0.5 seconds */
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
writel(OHCI_OCR, base + OHCI_CMDSTATUS);
while (wait_time > 0 &&
readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
wait_time -= 10;
msleep(10);
}
}
/*
* disable interrupts
*/
writel(~(u32)0, base + OHCI_INTRDISABLE);
writel(~(u32)0, base + OHCI_INTRSTATUS);
iounmap(base);
}
static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
{
int wait_time, delta;
void __iomem *base, *op_reg_base;
u32 hcc_params, val, temp;
u8 cap_length;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL) return;
cap_length = readb(base);
op_reg_base = base + cap_length;
hcc_params = readl(base + EHCI_HCC_PARAMS);
hcc_params = (hcc_params >> 8) & 0xff;
if (hcc_params) {
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
&val);
if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
/*
* Ok, BIOS is in smm mode, try to hand off...
*/
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
&temp);
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
temp | EHCI_USBLEGCTLSTS_SOOE);
val |= EHCI_USBLEGSUP_OS;
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
val);
wait_time = 500;
do {
msleep(10);
wait_time -= 10;
pci_read_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
&val);
} while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
if (!wait_time) {
/*
* well, possibly buggy BIOS...
*/
printk(KERN_WARNING "EHCI early BIOS handoff "
"failed (BIOS bug ?)\n");
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGSUP,
EHCI_USBLEGSUP_OS);
pci_write_config_dword(pdev,
hcc_params + EHCI_USBLEGCTLSTS,
0);
}
}
}
/*
* halt EHCI & disable its interrupts in any case
*/
val = readl(op_reg_base + EHCI_USBSTS);
if ((val & EHCI_USBSTS_HALTED) == 0) {
val = readl(op_reg_base + EHCI_USBCMD);
val &= ~EHCI_USBCMD_RUN;
writel(val, op_reg_base + EHCI_USBCMD);
wait_time = 2000;
delta = 100;
do {
writel(0x3f, op_reg_base + EHCI_USBSTS);
udelay(delta);
wait_time -= delta;
val = readl(op_reg_base + EHCI_USBSTS);
if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
break;
}
} while (wait_time > 0);
}
writel(0, op_reg_base + EHCI_USBINTR);
writel(0x3f, op_reg_base + EHCI_USBSTS);
iounmap(base);
return;
}
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
{
if (!usb_early_handoff)
return;
if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
quirk_usb_handoff_uhci(pdev);
} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
quirk_usb_handoff_ohci(pdev);
} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
quirk_usb_disable_ehci(pdev);
}
return;
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
/* /*
* ... This is further complicated by the fact that some SiS96x south * ... This is further complicated by the fact that some SiS96x south
* bridges pretend to be 85C503/5513 instead. In that case see if we * bridges pretend to be 85C503/5513 instead. In that case see if we
......
...@@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/ ...@@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_PCI) += host/
obj-$(CONFIG_USB_EHCI_HCD) += host/ obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_ISP116X_HCD) += host/ obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_OHCI_HCD) += host/
...@@ -17,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST) += host/ ...@@ -17,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_AUDIO) += class/ obj-$(CONFIG_USB_AUDIO) += class/
obj-$(CONFIG_USB_BLUETOOTH_TTY) += class/
obj-$(CONFIG_USB_MIDI) += class/ obj-$(CONFIG_USB_MIDI) += class/
obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_PRINTER) += class/
......
...@@ -28,29 +28,6 @@ config USB_AUDIO ...@@ -28,29 +28,6 @@ config USB_AUDIO
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called audio. module will be called audio.
comment "USB Bluetooth TTY can only be used with disabled Bluetooth subsystem"
depends on USB && BT
config USB_BLUETOOTH_TTY
tristate "USB Bluetooth TTY support"
depends on USB && BT=n
---help---
This driver implements a nonstandard tty interface to a Bluetooth
device that can be used only by specialized Bluetooth HCI software.
Say Y here if you want to use OpenBT Bluetooth stack (available
at <http://developer.axis.com/software>), or other TTY based
Bluetooth stacks, and want to connect a USB Bluetooth device
to your computer's USB port.
Do *not* enable this driver if you want to use generic Linux
Bluetooth support.
If in doubt, say N here.
To compile this driver as a module, choose M here: the
module will be called bluetty.
config USB_MIDI config USB_MIDI
tristate "USB MIDI support" tristate "USB MIDI support"
depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
......
...@@ -5,6 +5,5 @@ ...@@ -5,6 +5,5 @@
obj-$(CONFIG_USB_ACM) += cdc-acm.o obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_AUDIO) += audio.o obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_BLUETOOTH_TTY) += bluetty.o
obj-$(CONFIG_USB_MIDI) += usb-midi.o obj-$(CONFIG_USB_MIDI) += usb-midi.o
obj-$(CONFIG_USB_PRINTER) += usblp.o obj-$(CONFIG_USB_PRINTER) += usblp.o
This diff is collapsed.
...@@ -827,11 +827,10 @@ static int acm_probe (struct usb_interface *intf, ...@@ -827,11 +827,10 @@ static int acm_probe (struct usb_interface *intf,
return -ENODEV; return -ENODEV;
} }
if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
goto alloc_fail; goto alloc_fail;
} }
memset(acm, 0, sizeof(struct acm));
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
readsize = le16_to_cpu(epread->wMaxPacketSize); readsize = le16_to_cpu(epread->wMaxPacketSize);
......
...@@ -844,9 +844,8 @@ static struct file_operations usblp_fops = { ...@@ -844,9 +844,8 @@ static struct file_operations usblp_fops = {
}; };
static struct usb_class_driver usblp_class = { static struct usb_class_driver usblp_class = {
.name = "usb/lp%d", .name = "lp%d",
.fops = &usblp_fops, .fops = &usblp_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
.minor_base = USBLP_MINOR_BASE, .minor_base = USBLP_MINOR_BASE,
}; };
......
...@@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS ...@@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here. If you are unsure about this, say N here.
config USB_SUSPEND config USB_SUSPEND
bool "USB suspend/resume (EXPERIMENTAL)" bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
depends on USB && PM && EXPERIMENTAL depends on USB && PM && EXPERIMENTAL
help help
If you say Y here, you can use driver calls or the sysfs If you say Y here, you can use driver calls or the sysfs
"power/state" file to suspend or resume individual USB "power/state" file to suspend or resume individual USB
peripherals. There are many related features, such as peripherals.
remote wakeup and driver-specific suspend processing, that
may not yet work as expected. Also, USB "remote wakeup" signaling is supported, whereby some
USB devices (like keyboards and network adapters) can wake up
their parent hub. That wakeup cascades up the USB tree, and
could wake the system from states like suspend-to-RAM.
If you are unsure about this, say N here. If you are unsure about this, say N here.
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \ usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
config.o file.o buffer.o sysfs.o devio.o config.o file.o buffer.o sysfs.o devio.o notify.o
ifeq ($(CONFIG_PCI),y) ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o usbcore-objs += hcd-pci.o
......
...@@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref) ...@@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref)
struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
int j; int j;
for (j = 0; j < intfc->num_altsetting; j++) for (j = 0; j < intfc->num_altsetting; j++) {
kfree(intfc->altsetting[j].endpoint); struct usb_host_interface *alt = &intfc->altsetting[j];
kfree(alt->endpoint);
kfree(alt->string);
}
kfree(intfc); kfree(intfc);
} }
...@@ -188,10 +192,9 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -188,10 +192,9 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
} }
len = sizeof(struct usb_host_endpoint) * num_ep; len = sizeof(struct usb_host_endpoint) * num_ep;
alt->endpoint = kmalloc(len, GFP_KERNEL); alt->endpoint = kzalloc(len, GFP_KERNEL);
if (!alt->endpoint) if (!alt->endpoint)
return -ENOMEM; return -ENOMEM;
memset(alt->endpoint, 0, len);
/* Parse all the endpoint descriptors */ /* Parse all the endpoint descriptors */
n = 0; n = 0;
...@@ -353,10 +356,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -353,10 +356,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
} }
len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
config->intf_cache[i] = intfc = kmalloc(len, GFP_KERNEL); config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
if (!intfc) if (!intfc)
return -ENOMEM; return -ENOMEM;
memset(intfc, 0, len);
kref_init(&intfc->ref); kref_init(&intfc->ref);
} }
...@@ -422,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev) ...@@ -422,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev)
struct usb_host_config *cf = &dev->config[c]; struct usb_host_config *cf = &dev->config[c];
kfree(cf->string); kfree(cf->string);
cf->string = NULL;
for (i = 0; i < cf->desc.bNumInterfaces; i++) { for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i]) if (cf->intf_cache[i])
kref_put(&cf->intf_cache[i]->ref, kref_put(&cf->intf_cache[i]->ref,
...@@ -459,16 +459,14 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -459,16 +459,14 @@ int usb_get_configuration(struct usb_device *dev)
} }
length = ncfg * sizeof(struct usb_host_config); length = ncfg * sizeof(struct usb_host_config);
dev->config = kmalloc(length, GFP_KERNEL); dev->config = kzalloc(length, GFP_KERNEL);
if (!dev->config) if (!dev->config)
goto err2; goto err2;
memset(dev->config, 0, length);
length = ncfg * sizeof(char *); length = ncfg * sizeof(char *);
dev->rawdescriptors = kmalloc(length, GFP_KERNEL); dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
if (!dev->rawdescriptors) if (!dev->rawdescriptors)
goto err2; goto err2;
memset(dev->rawdescriptors, 0, length);
buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer) if (!buffer)
......
This diff is collapsed.
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -88,8 +87,6 @@ int usb_major_init(void) ...@@ -88,8 +87,6 @@ int usb_major_init(void)
goto out; goto out;
} }
devfs_mk_dir("usb");
out: out:
return error; return error;
} }
...@@ -97,7 +94,6 @@ int usb_major_init(void) ...@@ -97,7 +94,6 @@ int usb_major_init(void)
void usb_major_cleanup(void) void usb_major_cleanup(void)
{ {
class_destroy(usb_class); class_destroy(usb_class);
devfs_remove("usb");
unregister_chrdev(USB_MAJOR, "usb"); unregister_chrdev(USB_MAJOR, "usb");
} }
...@@ -112,8 +108,7 @@ void usb_major_cleanup(void) ...@@ -112,8 +108,7 @@ void usb_major_cleanup(void)
* enabled, the minor number will be based on the next available free minor, * enabled, the minor number will be based on the next available free minor,
* starting at the class_driver->minor_base. * starting at the class_driver->minor_base.
* *
* This function also creates the devfs file for the usb device, if devfs * This function also creates a usb class device in the sysfs tree.
* is enabled, and creates a usb class device in the sysfs tree.
* *
* usb_deregister_dev() must be called when the driver is done with * usb_deregister_dev() must be called when the driver is done with
* the minor numbers given out by this function. * the minor numbers given out by this function.
...@@ -162,11 +157,8 @@ int usb_register_dev(struct usb_interface *intf, ...@@ -162,11 +157,8 @@ int usb_register_dev(struct usb_interface *intf,
intf->minor = minor; intf->minor = minor;
/* handle the devfs registration */
snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base);
devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name);
/* create a usb class device for this usb interface */ /* create a usb class device for this usb interface */
snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base);
temp = strrchr(name, '/'); temp = strrchr(name, '/');
if (temp && (temp[1] != 0x00)) if (temp && (temp[1] != 0x00))
++temp; ++temp;
...@@ -179,7 +171,6 @@ int usb_register_dev(struct usb_interface *intf, ...@@ -179,7 +171,6 @@ int usb_register_dev(struct usb_interface *intf,
spin_lock (&minor_lock); spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL; usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock); spin_unlock (&minor_lock);
devfs_remove (name);
retval = PTR_ERR(intf->class_dev); retval = PTR_ERR(intf->class_dev);
} }
exit: exit:
...@@ -197,8 +188,7 @@ EXPORT_SYMBOL(usb_register_dev); ...@@ -197,8 +188,7 @@ EXPORT_SYMBOL(usb_register_dev);
* call to usb_register_dev() (usually when the device is disconnected * call to usb_register_dev() (usually when the device is disconnected
* from the system.) * from the system.)
* *
* This function also cleans up the devfs file for the usb device, if devfs * This function also removes the usb class device from the sysfs tree.
* is enabled, and removes the usb class device from the sysfs tree.
* *
* This should be called by all drivers that use the USB major number. * This should be called by all drivers that use the USB major number.
*/ */
...@@ -222,7 +212,6 @@ void usb_deregister_dev(struct usb_interface *intf, ...@@ -222,7 +212,6 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock); spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
devfs_remove (name);
class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor));
intf->class_dev = NULL; intf->class_dev = NULL;
intf->minor = -1; intf->minor = -1;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/usb.h> #include <linux/usb.h>
#include "usb.h"
#include "hcd.h" #include "hcd.h"
...@@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) ...@@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
/* Root hub suspend should have stopped all downstream traffic,
* and all bus master traffic. And done so for both the interface
* and the stub usb_device (which we check here). But maybe it
* didn't; writing sysfs power/state files ignores such rules...
*
* We must ignore the FREEZE vs SUSPEND distinction here, because
* otherwise the swsusp will save (and restore) garbage state.
*/
if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
return -EBUSY;
if (hcd->driver->suspend) {
retval = hcd->driver->suspend(hcd, message);
if (retval) {
dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
retval);
goto done;
}
}
/* FIXME until the generic PM interfaces change a lot more, this /* FIXME until the generic PM interfaces change a lot more, this
* can't use PCI D1 and D2 states. For example, the confusion * can't use PCI D1 and D2 states. For example, the confusion
* between messages and states will need to vanish, and messages * between messages and states will need to vanish, and messages
...@@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) ...@@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
*/ */
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
switch (hcd->state) { /* Downstream ports from this root hub should already be quiesced, so
* there will be no DMA activity. Now we can shut down the upstream
/* entry if root hub wasn't yet suspended ... from sysfs, * link (except maybe for PME# resume signaling) and enter some PCI
* without autosuspend, or if USB_SUSPEND isn't configured. * low power state, if the hardware allows.
*/ */
case HC_STATE_RUNNING: if (hcd->state == HC_STATE_SUSPENDED) {
hcd->state = HC_STATE_QUIESCING;
retval = hcd->driver->suspend (hcd, message);
if (retval) {
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
break;
}
hcd->state = HC_STATE_SUSPENDED;
/* FALLTHROUGH */
/* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
* controller and/or root hub will already have been suspended,
* but it won't be ready for a PCI resume call.
*
* FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
* have been called, otherwise root hub timers still run ...
*/
case HC_STATE_SUSPENDED:
/* no DMA or IRQs except when HC is active */ /* no DMA or IRQs except when HC is active */
if (dev->current_state == PCI_D0) { if (dev->current_state == PCI_D0) {
pci_save_state (dev); pci_save_state (dev);
...@@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) ...@@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
if (!has_pci_pm) { if (!has_pci_pm) {
dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n"); dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
break; goto done;
} }
/* NOTE: dev->current_state becomes nonzero only here, and /* NOTE: dev->current_state becomes nonzero only here, and
...@@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) ...@@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
retval = pci_set_power_state (dev, PCI_D3hot); retval = pci_set_power_state (dev, PCI_D3hot);
if (retval == 0) { if (retval == 0) {
dev_dbg (hcd->self.controller, "--> PCI D3\n"); dev_dbg (hcd->self.controller, "--> PCI D3\n");
retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
if (retval) /* Ignore these return values. We rely on pci code to
break; * reject requests the hardware can't implement, rather
retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); * than coding the same thing.
} else if (retval < 0) { */
(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
} else {
dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
retval); retval);
(void) usb_hcd_pci_resume (dev); (void) usb_hcd_pci_resume (dev);
break;
} }
break;
default: } else {
dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n", dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
hcd->state); hcd->state);
WARN_ON(1); WARN_ON(1);
retval = -EINVAL; retval = -EINVAL;
break;
} }
/* update power_state **ONLY** to make sysfs happier */ done:
if (retval == 0) if (retval == 0)
dev->dev.power.power_state = message; dev->dev.power.power_state = PMSG_SUSPEND;
return retval; return retval;
} }
EXPORT_SYMBOL (usb_hcd_pci_suspend); EXPORT_SYMBOL (usb_hcd_pci_suspend);
...@@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
dev->current_state); dev->current_state);
} }
#endif #endif
retval = pci_enable_wake (dev, dev->current_state, 0); /* yes, ignore these results too... */
if (retval) { (void) pci_enable_wake (dev, dev->current_state, 0);
dev_err(hcd->self.controller, (void) pci_enable_wake (dev, PCI_D3cold, 0);
"can't enable_wake to %d, %d!\n",
dev->current_state, retval);
return retval;
}
retval = pci_enable_wake (dev, PCI_D3cold, 0);
if (retval) {
dev_err(hcd->self.controller,
"can't enable_wake to %d, %d!\n",
PCI_D3cold, retval);
return retval;
}
} else { } else {
/* Same basic cases: clean (powered/not), dirty */ /* Same basic cases: clean (powered/not), dirty */
dev_dbg(hcd->self.controller, "PCI legacy resume\n"); dev_dbg(hcd->self.controller, "PCI legacy resume\n");
...@@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
dev->dev.power.power_state = PMSG_ON; dev->dev.power.power_state = PMSG_ON;
hcd->state = HC_STATE_RESUMING;
hcd->saw_irq = 0; hcd->saw_irq = 0;
retval = hcd->driver->resume (hcd); if (hcd->driver->resume) {
if (!HC_IS_RUNNING (hcd->state)) { retval = hcd->driver->resume(hcd);
dev_dbg (hcd->self.controller, if (retval) {
"resume fail, retval %d\n", retval); dev_err (hcd->self.controller,
"PCI post-resume error %d!\n", retval);
usb_hc_died (hcd); usb_hc_died (hcd);
} }
}
retval = pci_enable_device(dev);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_hcd_pci_resume); EXPORT_SYMBOL (usb_hcd_pci_resume);
......
...@@ -130,7 +130,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { ...@@ -130,7 +130,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceSubClass; */
0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idVendor; */
0x00, 0x00, /* __le16 idProduct; */ 0x00, 0x00, /* __le16 idProduct; */
...@@ -153,7 +153,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { ...@@ -153,7 +153,7 @@ static const u8 usb11_rh_dev_descriptor [18] = {
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */ 0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x00, 0x00, /* __le16 idVendor; */ 0x00, 0x00, /* __le16 idVendor; */
0x00, 0x00, /* __le16 idProduct; */ 0x00, 0x00, /* __le16 idProduct; */
...@@ -458,9 +458,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -458,9 +458,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
default: default:
/* non-generic request */ /* non-generic request */
if (HC_IS_SUSPENDED (hcd->state))
status = -EAGAIN;
else {
switch (typeReq) { switch (typeReq) {
case GetHubStatus: case GetHubStatus:
case GetPortStatus: case GetPortStatus:
...@@ -473,7 +470,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -473,7 +470,6 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
status = hcd->driver->hub_control (hcd, status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex, typeReq, wValue, wIndex,
tbuf, wLength); tbuf, wLength);
}
break; break;
error: error:
/* "protocol stall" on error */ /* "protocol stall" on error */
...@@ -487,7 +483,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -487,7 +483,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
"CTRL: TypeReq=0x%x val=0x%x " "CTRL: TypeReq=0x%x val=0x%x "
"idx=0x%x len=%d ==> %d\n", "idx=0x%x len=%d ==> %d\n",
typeReq, wValue, wIndex, typeReq, wValue, wIndex,
wLength, urb->status); wLength, status);
} }
} }
if (len) { if (len) {
...@@ -748,10 +744,9 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op) ...@@ -748,10 +744,9 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op)
{ {
struct usb_bus *bus; struct usb_bus *bus;
bus = kmalloc (sizeof *bus, GFP_KERNEL); bus = kzalloc (sizeof *bus, GFP_KERNEL);
if (!bus) if (!bus)
return NULL; return NULL;
memset(bus, 0, sizeof(struct usb_bus));
usb_bus_init (bus); usb_bus_init (bus);
bus->op = op; bus->op = op;
return bus; return bus;
...@@ -796,8 +791,7 @@ static int usb_register_bus(struct usb_bus *bus) ...@@ -796,8 +791,7 @@ static int usb_register_bus(struct usb_bus *bus)
list_add (&bus->bus_list, &usb_bus_list); list_add (&bus->bus_list, &usb_bus_list);
up (&usb_bus_list_lock); up (&usb_bus_list_lock);
usbfs_add_bus (bus); usb_notify_add_bus(bus);
usbmon_notify_bus_add (bus);
dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum); dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
return 0; return 0;
...@@ -824,8 +818,7 @@ static void usb_deregister_bus (struct usb_bus *bus) ...@@ -824,8 +818,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
list_del (&bus->bus_list); list_del (&bus->bus_list);
up (&usb_bus_list_lock); up (&usb_bus_list_lock);
usbmon_notify_bus_remove (bus); usb_notify_remove_bus(bus);
usbfs_remove_bus (bus);
clear_bit (bus->busnum, busmap.busmap); clear_bit (bus->busnum, busmap.busmap);
...@@ -1143,10 +1136,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) ...@@ -1143,10 +1136,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
else switch (hcd->state) { else switch (hcd->state) {
case HC_STATE_RUNNING: case HC_STATE_RUNNING:
case HC_STATE_RESUMING: case HC_STATE_RESUMING:
doit:
usb_get_dev (urb->dev); usb_get_dev (urb->dev);
list_add_tail (&urb->urb_list, &ep->urb_list); list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0; status = 0;
break; break;
case HC_STATE_SUSPENDED:
/* HC upstream links (register access, wakeup signaling) can work
* even when the downstream links (and DMA etc) are quiesced; let
* usbcore talk to the root hub.
*/
if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
&& urb->dev->parent == NULL)
goto doit;
/* FALL THROUGH */
default: default:
status = -ESHUTDOWN; status = -ESHUTDOWN;
break; break;
...@@ -1294,12 +1297,6 @@ static int hcd_unlink_urb (struct urb *urb, int status) ...@@ -1294,12 +1297,6 @@ static int hcd_unlink_urb (struct urb *urb, int status)
goto done; goto done;
} }
/* running ~= hc unlink handshake works (irq, timer, etc)
* halted ~= no unlink handshake is needed
* suspended, resuming == should never happen
*/
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
/* insist the urb is still queued */ /* insist the urb is still queued */
list_for_each(tmp, &ep->urb_list) { list_for_each(tmp, &ep->urb_list) {
if (tmp == &urb->urb_list) if (tmp == &urb->urb_list)
...@@ -1431,28 +1428,92 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) ...@@ -1431,28 +1428,92 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
static int hcd_hub_suspend (struct usb_bus *bus) int hcd_bus_suspend (struct usb_bus *bus)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
int status;
hcd = container_of (bus, struct usb_hcd, self); hcd = container_of (bus, struct usb_hcd, self);
if (hcd->driver->hub_suspend) if (!hcd->driver->bus_suspend)
return hcd->driver->hub_suspend (hcd); return -ENOENT;
return 0; hcd->state = HC_STATE_QUIESCING;
status = hcd->driver->bus_suspend (hcd);
if (status == 0)
hcd->state = HC_STATE_SUSPENDED;
else
dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
"suspend", status);
return status;
} }
static int hcd_hub_resume (struct usb_bus *bus) int hcd_bus_resume (struct usb_bus *bus)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
int status;
hcd = container_of (bus, struct usb_hcd, self); hcd = container_of (bus, struct usb_hcd, self);
if (hcd->driver->hub_resume) if (!hcd->driver->bus_resume)
return hcd->driver->hub_resume (hcd); return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
return 0; return 0;
hcd->state = HC_STATE_RESUMING;
status = hcd->driver->bus_resume (hcd);
if (status == 0)
hcd->state = HC_STATE_RUNNING;
else {
dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
"resume", status);
usb_hc_died(hcd);
}
return status;
} }
/*
* usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
* @hcd: host controller for this root hub
*
* This call arranges that usb_hcd_resume_root_hub() is safe to call later;
* that the HCD's root hub polling is deactivated; and that the root's hub
* driver is suspended. HCDs may call this to autosuspend when their root
* hub's downstream ports are all inactive: unpowered, disconnected,
* disabled, or suspended.
*
* The HCD will autoresume on device connect change detection (using SRP
* or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
* from any ports that are suspended (if that is enabled). In most cases,
* overcurrent signaling (on powered ports) will also start autoresume.
*
* Always called with IRQs blocked.
*/
void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
{
struct urb *urb;
spin_lock (&hcd_root_hub_lock);
usb_suspend_root_hub (hcd->self.root_hub);
/* force status urb to complete/unlink while suspended */
if (hcd->status_urb) {
urb = hcd->status_urb;
urb->status = -ECONNRESET;
urb->hcpriv = NULL;
urb->actual_length = 0;
del_timer (&hcd->rh_timer);
hcd->poll_pending = 0;
hcd->status_urb = NULL;
} else
urb = NULL;
spin_unlock (&hcd_root_hub_lock);
hcd->state = HC_STATE_SUSPENDED;
if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
}
EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
/** /**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub * usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub * @hcd: host controller for this root hub
...@@ -1460,7 +1521,7 @@ static int hcd_hub_resume (struct usb_bus *bus) ...@@ -1460,7 +1521,7 @@ static int hcd_hub_resume (struct usb_bus *bus)
* The USB host controller calls this function when its root hub is * The USB host controller calls this function when its root hub is
* suspended (with the remote wakeup feature enabled) and a remote * suspended (with the remote wakeup feature enabled) and a remote
* wakeup request is received. It queues a request for khubd to * wakeup request is received. It queues a request for khubd to
* resume the root hub. * resume the root hub (that is, manage its downstream ports again).
*/ */
void usb_hcd_resume_root_hub (struct usb_hcd *hcd) void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
{ {
...@@ -1471,13 +1532,9 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) ...@@ -1471,13 +1532,9 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
usb_resume_root_hub (hcd->self.root_hub); usb_resume_root_hub (hcd->self.root_hub);
spin_unlock_irqrestore (&hcd_root_hub_lock, flags); spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
} }
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
#else
void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
{
}
#endif #endif
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1530,10 +1587,6 @@ static struct usb_operations usb_hcd_operations = { ...@@ -1530,10 +1587,6 @@ static struct usb_operations usb_hcd_operations = {
.buffer_alloc = hcd_buffer_alloc, .buffer_alloc = hcd_buffer_alloc,
.buffer_free = hcd_buffer_free, .buffer_free = hcd_buffer_free,
.disable = hcd_endpoint_disable, .disable = hcd_endpoint_disable,
#ifdef CONFIG_USB_SUSPEND
.hub_suspend = hcd_hub_suspend,
.hub_resume = hcd_hub_resume,
#endif
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -154,10 +154,6 @@ struct usb_operations { ...@@ -154,10 +154,6 @@ struct usb_operations {
void (*disable)(struct usb_device *udev, void (*disable)(struct usb_device *udev,
struct usb_host_endpoint *ep); struct usb_host_endpoint *ep);
/* global suspend/resume of bus */
int (*hub_suspend)(struct usb_bus *);
int (*hub_resume)(struct usb_bus *);
}; };
/* each driver provides one of these, and hardware init support */ /* each driver provides one of these, and hardware init support */
...@@ -182,12 +178,12 @@ struct hc_driver { ...@@ -182,12 +178,12 @@ struct hc_driver {
int (*start) (struct usb_hcd *hcd); int (*start) (struct usb_hcd *hcd);
/* NOTE: these suspend/resume calls relate to the HC as /* NOTE: these suspend/resume calls relate to the HC as
* a whole, not just the root hub; they're for bus glue. * a whole, not just the root hub; they're for PCI bus glue.
*/ */
/* called after all devices were suspended */ /* called after suspending the hub, before entering D3 etc */
int (*suspend) (struct usb_hcd *hcd, pm_message_t message); int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
/* called before any devices get resumed */ /* called after entering D0 (etc), before resuming the hub */
int (*resume) (struct usb_hcd *hcd); int (*resume) (struct usb_hcd *hcd);
/* cleanly make HCD stop writing memory and doing I/O */ /* cleanly make HCD stop writing memory and doing I/O */
...@@ -212,8 +208,8 @@ struct hc_driver { ...@@ -212,8 +208,8 @@ struct hc_driver {
int (*hub_control) (struct usb_hcd *hcd, int (*hub_control) (struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength); char *buf, u16 wLength);
int (*hub_suspend)(struct usb_hcd *); int (*bus_suspend)(struct usb_hcd *);
int (*hub_resume)(struct usb_hcd *); int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num); int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
void (*hub_irq_enable)(struct usb_hcd *); void (*hub_irq_enable)(struct usb_hcd *);
/* Needed only if port-change IRQs are level-triggered */ /* Needed only if port-change IRQs are level-triggered */
...@@ -355,8 +351,6 @@ extern long usb_calc_bus_time (int speed, int is_input, ...@@ -355,8 +351,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
extern struct usb_bus *usb_alloc_bus (struct usb_operations *); extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_set_device_state(struct usb_device *udev, extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state); enum usb_device_state new_state);
...@@ -378,6 +372,33 @@ extern int usb_find_interface_driver (struct usb_device *dev, ...@@ -378,6 +372,33 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern int hcd_bus_suspend (struct usb_bus *bus);
extern int hcd_bus_resume (struct usb_bus *bus);
#else
static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
{
return;
}
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
static inline int hcd_bus_suspend(struct usb_bus *bus)
{
return 0;
}
static inline int hcd_bus_resume (struct usb_bus *bus)
{
return 0;
}
#endif /* CONFIG_PM */
/* /*
* USB device fs stuff * USB device fs stuff
*/ */
...@@ -388,23 +409,13 @@ extern int usb_find_interface_driver (struct usb_device *dev, ...@@ -388,23 +409,13 @@ extern int usb_find_interface_driver (struct usb_device *dev,
* these are expected to be called from the USB core/hub thread * these are expected to be called from the USB core/hub thread
* with the kernel lock held * with the kernel lock held
*/ */
extern void usbfs_add_bus(struct usb_bus *bus);
extern void usbfs_remove_bus(struct usb_bus *bus);
extern void usbfs_add_device(struct usb_device *dev);
extern void usbfs_remove_device(struct usb_device *dev);
extern void usbfs_update_special (void); extern void usbfs_update_special (void);
extern int usbfs_init(void); extern int usbfs_init(void);
extern void usbfs_cleanup(void); extern void usbfs_cleanup(void);
#else /* CONFIG_USB_DEVICEFS */ #else /* CONFIG_USB_DEVICEFS */
static inline void usbfs_add_bus(struct usb_bus *bus) {}
static inline void usbfs_remove_bus(struct usb_bus *bus) {}
static inline void usbfs_add_device(struct usb_device *dev) {}
static inline void usbfs_remove_device(struct usb_device *dev) {}
static inline void usbfs_update_special (void) {} static inline void usbfs_update_special (void) {}
static inline int usbfs_init(void) { return 0; } static inline int usbfs_init(void) { return 0; }
static inline void usbfs_cleanup(void) { } static inline void usbfs_cleanup(void) { }
...@@ -419,8 +430,6 @@ struct usb_mon_operations { ...@@ -419,8 +430,6 @@ struct usb_mon_operations {
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err); void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
void (*urb_complete)(struct usb_bus *bus, struct urb *urb); void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */ /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
void (*bus_add)(struct usb_bus *bus);
void (*bus_remove)(struct usb_bus *bus);
}; };
extern struct usb_mon_operations *mon_ops; extern struct usb_mon_operations *mon_ops;
...@@ -444,18 +453,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) ...@@ -444,18 +453,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
(*mon_ops->urb_complete)(bus, urb); (*mon_ops->urb_complete)(bus, urb);
} }
static inline void usbmon_notify_bus_add(struct usb_bus *bus)
{
if (mon_ops)
(*mon_ops->bus_add)(bus);
}
static inline void usbmon_notify_bus_remove(struct usb_bus *bus)
{
if (mon_ops)
(*mon_ops->bus_remove)(bus);
}
int usb_mon_register(struct usb_mon_operations *ops); int usb_mon_register(struct usb_mon_operations *ops);
void usb_mon_deregister(void); void usb_mon_deregister(void);
...@@ -465,8 +462,6 @@ static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {} ...@@ -465,8 +462,6 @@ 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, static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {} int error) {}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {} static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_notify_bus_add(struct usb_bus *bus) {}
static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {}
#endif /* CONFIG_USB_MON */ #endif /* CONFIG_USB_MON */
......
This diff is collapsed.
...@@ -131,7 +131,7 @@ struct usb_hub_descriptor { ...@@ -131,7 +131,7 @@ struct usb_hub_descriptor {
__u8 bDescLength; __u8 bDescLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bNbrPorts; __u8 bNbrPorts;
__u16 wHubCharacteristics; __le16 wHubCharacteristics;
__u8 bPwrOn2PwrGood; __u8 bPwrOn2PwrGood;
__u8 bHubContrCurrent; __u8 bHubContrCurrent;
/* add 1 bit for hub status change; round to bytes */ /* add 1 bit for hub status change; round to bytes */
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/usbdevice_fs.h> #include <linux/usbdevice_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/notifier.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "usb.h" #include "usb.h"
#include "hcd.h" #include "hcd.h"
...@@ -619,7 +620,7 @@ void usbfs_update_special (void) ...@@ -619,7 +620,7 @@ void usbfs_update_special (void)
} }
} }
void usbfs_add_bus(struct usb_bus *bus) static void usbfs_add_bus(struct usb_bus *bus)
{ {
struct dentry *parent; struct dentry *parent;
char name[8]; char name[8];
...@@ -642,12 +643,9 @@ void usbfs_add_bus(struct usb_bus *bus) ...@@ -642,12 +643,9 @@ void usbfs_add_bus(struct usb_bus *bus)
err ("error creating usbfs bus entry"); err ("error creating usbfs bus entry");
return; return;
} }
usbfs_update_special();
usbfs_conn_disc_event();
} }
void usbfs_remove_bus(struct usb_bus *bus) static void usbfs_remove_bus(struct usb_bus *bus)
{ {
if (bus->usbfs_dentry) { if (bus->usbfs_dentry) {
fs_remove_file (bus->usbfs_dentry); fs_remove_file (bus->usbfs_dentry);
...@@ -659,12 +657,9 @@ void usbfs_remove_bus(struct usb_bus *bus) ...@@ -659,12 +657,9 @@ void usbfs_remove_bus(struct usb_bus *bus)
remove_special_files(); remove_special_files();
num_buses = 0; num_buses = 0;
} }
usbfs_update_special();
usbfs_conn_disc_event();
} }
void usbfs_add_device(struct usb_device *dev) static void usbfs_add_device(struct usb_device *dev)
{ {
char name[8]; char name[8];
int i; int i;
...@@ -690,12 +685,9 @@ void usbfs_add_device(struct usb_device *dev) ...@@ -690,12 +685,9 @@ void usbfs_add_device(struct usb_device *dev)
} }
if (dev->usbfs_dentry->d_inode) if (dev->usbfs_dentry->d_inode)
dev->usbfs_dentry->d_inode->i_size = i_size; dev->usbfs_dentry->d_inode->i_size = i_size;
usbfs_update_special();
usbfs_conn_disc_event();
} }
void usbfs_remove_device(struct usb_device *dev) static void usbfs_remove_device(struct usb_device *dev)
{ {
struct dev_state *ds; struct dev_state *ds;
struct siginfo sinfo; struct siginfo sinfo;
...@@ -716,10 +708,33 @@ void usbfs_remove_device(struct usb_device *dev) ...@@ -716,10 +708,33 @@ void usbfs_remove_device(struct usb_device *dev)
kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid); kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid);
} }
} }
}
static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
usbfs_add_device(dev);
break;
case USB_DEVICE_REMOVE:
usbfs_remove_device(dev);
break;
case USB_BUS_ADD:
usbfs_add_bus(dev);
break;
case USB_BUS_REMOVE:
usbfs_remove_bus(dev);
}
usbfs_update_special(); usbfs_update_special();
usbfs_conn_disc_event(); usbfs_conn_disc_event();
return NOTIFY_OK;
} }
static struct notifier_block usbfs_nb = {
.notifier_call = usbfs_notify,
};
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static struct proc_dir_entry *usbdir = NULL; static struct proc_dir_entry *usbdir = NULL;
...@@ -732,6 +747,8 @@ int __init usbfs_init(void) ...@@ -732,6 +747,8 @@ int __init usbfs_init(void)
if (retval) if (retval)
return retval; return retval;
usb_register_notify(&usbfs_nb);
/* create mount point for usbfs */ /* create mount point for usbfs */
usbdir = proc_mkdir("usb", proc_bus); usbdir = proc_mkdir("usb", proc_bus);
...@@ -740,6 +757,7 @@ int __init usbfs_init(void) ...@@ -740,6 +757,7 @@ int __init usbfs_init(void)
void usbfs_cleanup(void) void usbfs_cleanup(void)
{ {
usb_unregister_notify(&usbfs_nb);
unregister_filesystem(&usb_fs_type); unregister_filesystem(&usb_fs_type);
if (usbdir) if (usbdir)
remove_proc_entry("usb", proc_bus); remove_proc_entry("usb", proc_bus);
......
...@@ -187,19 +187,35 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u ...@@ -187,19 +187,35 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
* If a thread in your driver uses this call, make sure your disconnect() * If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on * method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request. * the URB used, you can't cancel the request.
*
* Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
* ioctl, users are forced to abuse this routine by using it to submit
* URBs for interrupt endpoints. We will take the liberty of creating
* an interrupt URB (with the default interval) if the target is an
* interrupt endpoint.
*/ */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout) void *data, int len, int *actual_length, int timeout)
{ {
struct urb *urb; struct urb *urb;
struct usb_host_endpoint *ep;
if (len < 0) ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
[usb_pipeendpoint(pipe)];
if (!ep || len < 0)
return -EINVAL; return -EINVAL;
urb=usb_alloc_urb(0, GFP_KERNEL); urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) if (!urb)
return -ENOMEM; return -ENOMEM;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT) {
pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval);
} else
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL); usb_api_blocking_completion, NULL);
...@@ -771,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) ...@@ -771,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
return err; return err;
} }
/**
* usb_cache_string - read a string descriptor and cache it for later use
* @udev: the device whose string descriptor is being read
* @index: the descriptor index
*
* Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
* or NULL if the index is 0 or the string could not be read.
*/
char *usb_cache_string(struct usb_device *udev, int index)
{
char *buf;
char *smallbuf = NULL;
int len;
if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
if ((len = usb_string(udev, index, buf, 256)) > 0) {
if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
return buf;
memcpy(smallbuf, buf, len);
}
kfree(buf);
}
return smallbuf;
}
/* /*
* usb_get_device_descriptor - (re)reads the device descriptor (usbcore) * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
* @dev: the device whose device descriptor is being updated * @dev: the device whose device descriptor is being updated
...@@ -992,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) ...@@ -992,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
dev_dbg (&dev->dev, "unregistering interface %s\n", dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id); interface->dev.bus_id);
usb_remove_sysfs_intf_files(interface); usb_remove_sysfs_intf_files(interface);
kfree(interface->cur_altsetting->string);
interface->cur_altsetting->string = NULL;
device_del (&interface->dev); device_del (&interface->dev);
} }
...@@ -1133,6 +1172,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) ...@@ -1133,6 +1172,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/ */
/* prevent submissions using previous endpoint settings */ /* prevent submissions using previous endpoint settings */
if (device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface); usb_disable_interface(dev, iface);
iface->cur_altsetting = alt; iface->cur_altsetting = alt;
...@@ -1168,6 +1209,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) ...@@ -1168,6 +1209,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.) * (Likewise, EP0 never "halts" on well designed devices.)
*/ */
usb_enable_interface(dev, iface); usb_enable_interface(dev, iface);
if (device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0; return 0;
} }
...@@ -1217,10 +1260,8 @@ int usb_reset_configuration(struct usb_device *dev) ...@@ -1217,10 +1260,8 @@ int usb_reset_configuration(struct usb_device *dev)
USB_REQ_SET_CONFIGURATION, 0, USB_REQ_SET_CONFIGURATION, 0,
config->desc.bConfigurationValue, 0, config->desc.bConfigurationValue, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT); NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) { if (retval < 0)
usb_set_device_state(dev, USB_STATE_ADDRESS);
return retval; return retval;
}
dev->toggle[0] = dev->toggle[1] = 0; dev->toggle[0] = dev->toggle[1] = 0;
...@@ -1229,6 +1270,8 @@ int usb_reset_configuration(struct usb_device *dev) ...@@ -1229,6 +1270,8 @@ int usb_reset_configuration(struct usb_device *dev)
struct usb_interface *intf = config->interface[i]; struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt; struct usb_host_interface *alt;
if (device_is_registered(&intf->dev))
usb_remove_sysfs_intf_files(intf);
alt = usb_altnum_to_altsetting(intf, 0); alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting. /* No altsetting 0? We'll assume the first altsetting.
...@@ -1241,6 +1284,8 @@ int usb_reset_configuration(struct usb_device *dev) ...@@ -1241,6 +1284,8 @@ int usb_reset_configuration(struct usb_device *dev)
intf->cur_altsetting = alt; intf->cur_altsetting = alt;
usb_enable_interface(dev, intf); usb_enable_interface(dev, intf);
if (device_is_registered(&intf->dev))
usb_create_sysfs_intf_files(intf);
} }
return 0; return 0;
} }
...@@ -1328,7 +1373,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1328,7 +1373,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
} }
for (; n < nintf; ++n) { for (; n < nintf; ++n) {
new_interfaces[n] = kmalloc( new_interfaces[n] = kzalloc(
sizeof(struct usb_interface), sizeof(struct usb_interface),
GFP_KERNEL); GFP_KERNEL);
if (!new_interfaces[n]) { if (!new_interfaces[n]) {
...@@ -1369,7 +1414,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1369,7 +1414,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_host_interface *alt; struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i]; cp->interface[i] = intf = new_interfaces[i];
memset(intf, 0, sizeof(*intf));
intfc = cp->intf_cache[i]; intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting; intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting; intf->num_altsetting = intfc->num_altsetting;
...@@ -1393,6 +1437,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1393,6 +1437,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.dma_mask = dev->dev.dma_mask;
intf->dev.release = release_interface; intf->dev.release = release_interface;
device_initialize (&intf->dev); device_initialize (&intf->dev);
mark_quiesced(intf);
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath, dev->bus->busnum, dev->devpath,
configuration, configuration,
...@@ -1400,12 +1445,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1400,12 +1445,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
} }
kfree(new_interfaces); kfree(new_interfaces);
if ((cp->desc.iConfiguration) && if (cp->string == NULL)
(cp->string == NULL)) { cp->string = usb_cache_string(dev,
cp->string = kmalloc(256, GFP_KERNEL); cp->desc.iConfiguration);
if (cp->string)
usb_string(dev, cp->desc.iConfiguration, cp->string, 256);
}
/* Now that all the interfaces are set up, register them /* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe() * to trigger binding of drivers to interfaces. probe()
...@@ -1415,13 +1457,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1415,13 +1457,12 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
*/ */
for (i = 0; i < nintf; ++i) { for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i]; struct usb_interface *intf = cp->interface[i];
struct usb_interface_descriptor *desc; struct usb_host_interface *alt = intf->cur_altsetting;
desc = &intf->altsetting [0].desc;
dev_dbg (&dev->dev, dev_dbg (&dev->dev,
"adding %s (config #%d, interface %d)\n", "adding %s (config #%d, interface %d)\n",
intf->dev.bus_id, configuration, intf->dev.bus_id, configuration,
desc->bInterfaceNumber); alt->desc.bInterfaceNumber);
ret = device_add (&intf->dev); ret = device_add (&intf->dev);
if (ret != 0) { if (ret != 0) {
dev_err(&dev->dev, dev_err(&dev->dev,
...@@ -1430,13 +1471,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1430,13 +1471,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
ret); ret);
continue; continue;
} }
if ((intf->cur_altsetting->desc.iInterface) &&
(intf->cur_altsetting->string == NULL)) {
intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL);
if (intf->cur_altsetting->string)
usb_string(dev, intf->cur_altsetting->desc.iInterface,
intf->cur_altsetting->string, 256);
}
usb_create_sysfs_intf_files (intf); usb_create_sysfs_intf_files (intf);
} }
} }
......
/*
* All the USB notify logic
*
* (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
*
* notifier functions originally based on those in kernel/sys.c
* but fixed up to not be so broken.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
#include "usb.h"
static struct notifier_block *usb_notifier_list;
static DECLARE_MUTEX(usb_notifier_lock);
static void usb_notifier_chain_register(struct notifier_block **list,
struct notifier_block *n)
{
down(&usb_notifier_lock);
while (*list) {
if (n->priority > (*list)->priority)
break;
list = &((*list)->next);
}
n->next = *list;
*list = n;
up(&usb_notifier_lock);
}
static void usb_notifier_chain_unregister(struct notifier_block **nl,
struct notifier_block *n)
{
down(&usb_notifier_lock);
while ((*nl)!=NULL) {
if ((*nl)==n) {
*nl = n->next;
goto exit;
}
nl=&((*nl)->next);
}
exit:
up(&usb_notifier_lock);
}
static int usb_notifier_call_chain(struct notifier_block **n,
unsigned long val, void *v)
{
int ret=NOTIFY_DONE;
struct notifier_block *nb = *n;
down(&usb_notifier_lock);
while (nb) {
ret = nb->notifier_call(nb,val,v);
if (ret&NOTIFY_STOP_MASK) {
goto exit;
}
nb = nb->next;
}
exit:
up(&usb_notifier_lock);
return ret;
}
/**
* usb_register_notify - register a notifier callback whenever a usb change happens
* @nb: pointer to the notifier block for the callback events.
*
* These changes are either USB devices or busses being added or removed.
*/
void usb_register_notify(struct notifier_block *nb)
{
usb_notifier_chain_register(&usb_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(usb_register_notify);
/**
* usb_unregister_notify - unregister a notifier callback
* @nb: pointer to the notifier block for the callback events.
*
* usb_register_notifier() must have been previously called for this function
* to work properly.
*/
void usb_unregister_notify(struct notifier_block *nb)
{
usb_notifier_chain_unregister(&usb_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(usb_unregister_notify);
void usb_notify_add_device(struct usb_device *udev)
{
usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
}
void usb_notify_remove_device(struct usb_device *udev)
{
usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
}
void usb_notify_add_bus(struct usb_bus *ubus)
{
usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
}
void usb_notify_remove_bus(struct usb_bus *ubus)
{
usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
}
This diff is collapsed.
...@@ -237,7 +237,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -237,7 +237,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
(dev->state < USB_STATE_DEFAULT) || (dev->state < USB_STATE_DEFAULT) ||
(!dev->bus) || (dev->devnum <= 0)) (!dev->bus) || (dev->devnum <= 0))
return -ENODEV; return -ENODEV;
if (dev->state == USB_STATE_SUSPENDED) if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH; return -EHOSTUNREACH;
if (!(op = dev->bus->op) || !op->submit_urb) if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV; return -ENODEV;
......
...@@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev) ...@@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev)
id = usb_match_id (intf, driver->id_table); id = usb_match_id (intf, driver->id_table);
if (id) { if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__); dev_dbg (dev, "%s - got id\n", __FUNCTION__);
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING; intf->condition = USB_INTERFACE_BINDING;
error = driver->probe (intf, id); error = driver->probe (intf, id);
intf->condition = error ? USB_INTERFACE_UNBOUND : if (error) {
USB_INTERFACE_BOUND; mark_quiesced(intf);
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
} }
return error; return error;
...@@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev) ...@@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev)
0); 0);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND; intf->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(intf);
return 0; return 0;
} }
...@@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
dev->driver = &driver->driver; dev->driver = &driver->driver;
usb_set_intfdata(iface, priv); usb_set_intfdata(iface, priv);
iface->condition = USB_INTERFACE_BOUND; iface->condition = USB_INTERFACE_BOUND;
mark_active(iface);
/* if interface was already added, bind now; else let /* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe() * the future device_add() bind it, bypassing probe()
...@@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver, ...@@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
dev->driver = NULL; dev->driver = NULL;
usb_set_intfdata(iface, NULL); usb_set_intfdata(iface, NULL);
iface->condition = USB_INTERFACE_UNBOUND; iface->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(iface);
} }
/** /**
...@@ -557,6 +569,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -557,6 +569,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct usb_host_interface *alt;
int i = 0; int i = 0;
int length = 0; int length = 0;
...@@ -573,6 +586,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -573,6 +586,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev (intf); usb_dev = interface_to_usbdev (intf);
alt = intf->cur_altsetting;
if (usb_dev->devnum < 0) { if (usb_dev->devnum < 0) {
pr_debug ("usb %s: already deleted?\n", dev->bus_id); pr_debug ("usb %s: already deleted?\n", dev->bus_id);
...@@ -615,13 +629,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -615,13 +629,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
usb_dev->descriptor.bDeviceProtocol)) usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM; return -ENOMEM;
if (usb_dev->descriptor.bDeviceClass == 0) {
struct usb_host_interface *alt = intf->cur_altsetting;
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
if (add_hotplug_env_var(envp, num_envp, &i, if (add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"INTERFACE=%d/%d/%d", "INTERFACE=%d/%d/%d",
...@@ -643,18 +650,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -643,18 +650,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
alt->desc.bInterfaceSubClass, alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol)) alt->desc.bInterfaceProtocol))
return -ENOMEM; return -ENOMEM;
} else {
if (add_hotplug_env_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice),
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
}
envp[i] = NULL; envp[i] = NULL;
...@@ -709,12 +704,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) ...@@ -709,12 +704,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{ {
struct usb_device *dev; struct usb_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) if (!dev)
return NULL; return NULL;
memset(dev, 0, sizeof(*dev));
bus = usb_bus_get(bus); bus = usb_bus_get(bus);
if (!bus) { if (!bus) {
kfree(dev); kfree(dev);
...@@ -1402,13 +1395,30 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1402,13 +1395,30 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
} }
static int verify_suspended(struct device *dev, void *unused)
{
return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
}
static int usb_generic_suspend(struct device *dev, pm_message_t message) static int usb_generic_suspend(struct device *dev, pm_message_t message)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
int status;
if (dev->driver == &usb_generic_driver) /* USB devices enter SUSPEND state through their hubs, but can be
return usb_suspend_device (to_usb_device(dev), message); * marked for FREEZE as soon as their children are already idled.
* But those semantics are useless, so we equate the two (sigh).
*/
if (dev->driver == &usb_generic_driver) {
if (dev->power.power_state.event == message.event)
return 0;
/* we need to rule out bogus requests through sysfs */
status = device_for_each_child(dev, NULL, verify_suspended);
if (status)
return status;
return usb_suspend_device (to_usb_device(dev));
}
if ((dev->driver == NULL) || if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data)) (dev->driver_data == &usb_generic_driver_data))
...@@ -1417,23 +1427,44 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) ...@@ -1417,23 +1427,44 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver); driver = to_usb_driver(dev->driver);
/* there's only one USB suspend state */ /* with no hardware, USB interfaces only use FREEZE and ON states */
if (intf->dev.power.power_state.event) if (!is_active(intf))
return 0; return 0;
if (driver->suspend) if (driver->suspend && driver->resume) {
return driver->suspend(intf, message); status = driver->suspend(intf, message);
return 0; if (status)
dev_err(dev, "%s error %d\n", "suspend", status);
else
mark_quiesced(intf);
} else {
// FIXME else if there's no suspend method, disconnect...
dev_warn(dev, "no %s?\n", "suspend");
status = 0;
}
return status;
} }
static int usb_generic_resume(struct device *dev) static int usb_generic_resume(struct device *dev)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
struct usb_device *udev;
int status;
/* devices resume through their hub */ if (dev->power.power_state.event == PM_EVENT_ON)
if (dev->driver == &usb_generic_driver) return 0;
/* mark things as "on" immediately, no matter what errors crop up */
dev->power.power_state.event = PM_EVENT_ON;
/* devices resume through their hubs */
if (dev->driver == &usb_generic_driver) {
udev = to_usb_device(dev);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
return usb_resume_device (to_usb_device(dev)); return usb_resume_device (to_usb_device(dev));
}
if ((dev->driver == NULL) || if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data)) (dev->driver_data == &usb_generic_driver_data))
...@@ -1442,8 +1473,22 @@ static int usb_generic_resume(struct device *dev) ...@@ -1442,8 +1473,22 @@ static int usb_generic_resume(struct device *dev)
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver); driver = to_usb_driver(dev->driver);
if (driver->resume) udev = interface_to_usbdev(intf);
return driver->resume(intf); if (udev->state == USB_STATE_NOTATTACHED)
return 0;
/* if driver was suspended, it has a resume method;
* however, sysfs can wrongly mark things as suspended
* (on the "no suspend method" FIXME path above)
*/
if (driver->resume) {
status = driver->resume(intf);
if (status) {
dev_err(dev, "%s error %d\n", "resume", status);
mark_quiesced(intf);
}
} else
dev_warn(dev, "no %s?\n", "resume");
return 0; return 0;
} }
......
...@@ -13,12 +13,14 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0); ...@@ -13,12 +13,14 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern int usb_get_device_descriptor(struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size); unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_lock_all_devices(void); extern void usb_lock_all_devices(void);
extern void usb_unlock_all_devices(void); extern void usb_unlock_all_devices(void);
extern void usb_kick_khubd(struct usb_device *dev); extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_suspend_root_hub(struct usb_device *hdev);
extern void usb_resume_root_hub(struct usb_device *dev); extern void usb_resume_root_hub(struct usb_device *dev);
extern int usb_hub_init(void); extern int usb_hub_init(void);
...@@ -28,6 +30,28 @@ extern void usb_major_cleanup(void); ...@@ -28,6 +30,28 @@ extern void usb_major_cleanup(void);
extern int usb_host_init(void); extern int usb_host_init(void);
extern void usb_host_cleanup(void); extern void usb_host_cleanup(void);
extern int usb_suspend_device(struct usb_device *dev);
extern int usb_resume_device(struct usb_device *dev);
/* Interfaces and their "power state" are owned by usbcore */
static inline void mark_active(struct usb_interface *f)
{
f->dev.power.power_state.event = PM_EVENT_ON;
}
static inline void mark_quiesced(struct usb_interface *f)
{
f->dev.power.power_state.event = PM_EVENT_FREEZE;
}
static inline int is_active(struct usb_interface *f)
{
return f->dev.power.power_state.event == PM_EVENT_ON;
}
/* for labeling diagnostics */ /* for labeling diagnostics */
extern const char *usbcore_name; extern const char *usbcore_name;
...@@ -39,9 +63,6 @@ extern void usbfs_conn_disc_event(void); ...@@ -39,9 +63,6 @@ extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void); extern int usbdev_init(void);
extern void usbdev_cleanup(void); extern void usbdev_cleanup(void);
extern void usbdev_add(struct usb_device *dev);
extern void usbdev_remove(struct usb_device *dev);
extern struct usb_device *usbdev_lookup_minor(int minor);
struct dev_state { struct dev_state {
struct list_head list; /* state list */ struct list_head list; /* state list */
...@@ -58,3 +79,9 @@ struct dev_state { ...@@ -58,3 +79,9 @@ struct dev_state {
unsigned long ifclaimed; unsigned long ifclaimed;
}; };
/* internal notify stuff */
extern void usb_notify_add_device(struct usb_device *udev);
extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
...@@ -967,6 +967,7 @@ static int dummy_udc_resume (struct device *dev) ...@@ -967,6 +967,7 @@ static int dummy_udc_resume (struct device *dev)
static struct device_driver dummy_udc_driver = { static struct device_driver dummy_udc_driver = {
.name = (char *) gadget_name, .name = (char *) gadget_name,
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = dummy_udc_probe, .probe = dummy_udc_probe,
.remove = dummy_udc_remove, .remove = dummy_udc_remove,
...@@ -1751,7 +1752,7 @@ static int dummy_hub_control ( ...@@ -1751,7 +1752,7 @@ static int dummy_hub_control (
return retval; return retval;
} }
static int dummy_hub_suspend (struct usb_hcd *hcd) static int dummy_bus_suspend (struct usb_hcd *hcd)
{ {
struct dummy *dum = hcd_to_dummy (hcd); struct dummy *dum = hcd_to_dummy (hcd);
...@@ -1762,7 +1763,7 @@ static int dummy_hub_suspend (struct usb_hcd *hcd) ...@@ -1762,7 +1763,7 @@ static int dummy_hub_suspend (struct usb_hcd *hcd)
return 0; return 0;
} }
static int dummy_hub_resume (struct usb_hcd *hcd) static int dummy_bus_resume (struct usb_hcd *hcd)
{ {
struct dummy *dum = hcd_to_dummy (hcd); struct dummy *dum = hcd_to_dummy (hcd);
...@@ -1894,8 +1895,8 @@ static const struct hc_driver dummy_hcd = { ...@@ -1894,8 +1895,8 @@ static const struct hc_driver dummy_hcd = {
.hub_status_data = dummy_hub_status, .hub_status_data = dummy_hub_status,
.hub_control = dummy_hub_control, .hub_control = dummy_hub_control,
.hub_suspend = dummy_hub_suspend, .bus_suspend = dummy_bus_suspend,
.hub_resume = dummy_hub_resume, .bus_resume = dummy_bus_resume,
}; };
static int dummy_hcd_probe (struct device *dev) static int dummy_hcd_probe (struct device *dev)
...@@ -1936,13 +1937,6 @@ static int dummy_hcd_suspend (struct device *dev, pm_message_t state) ...@@ -1936,13 +1937,6 @@ static int dummy_hcd_suspend (struct device *dev, pm_message_t state)
dev_dbg (dev, "%s\n", __FUNCTION__); dev_dbg (dev, "%s\n", __FUNCTION__);
hcd = dev_get_drvdata (dev); hcd = dev_get_drvdata (dev);
#ifndef CONFIG_USB_SUSPEND
/* Otherwise this would never happen */
usb_lock_device (hcd->self.root_hub);
dummy_hub_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
hcd->state = HC_STATE_SUSPENDED; hcd->state = HC_STATE_SUSPENDED;
return 0; return 0;
} }
...@@ -1955,19 +1949,13 @@ static int dummy_hcd_resume (struct device *dev) ...@@ -1955,19 +1949,13 @@ static int dummy_hcd_resume (struct device *dev)
hcd = dev_get_drvdata (dev); hcd = dev_get_drvdata (dev);
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
#ifndef CONFIG_USB_SUSPEND
/* Otherwise this would never happen */
usb_lock_device (hcd->self.root_hub);
dummy_hub_resume (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
usb_hcd_poll_rh_status (hcd); usb_hcd_poll_rh_status (hcd);
return 0; return 0;
} }
static struct device_driver dummy_hcd_driver = { static struct device_driver dummy_hcd_driver = {
.name = (char *) driver_name, .name = (char *) driver_name,
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = dummy_hcd_probe, .probe = dummy_hcd_probe,
.remove = dummy_hcd_remove, .remove = dummy_hcd_remove,
......
...@@ -2533,6 +2533,7 @@ static struct usb_gadget_driver eth_driver = { ...@@ -2533,6 +2533,7 @@ static struct usb_gadget_driver eth_driver = {
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
.owner = THIS_MODULE,
// .shutdown = ... // .shutdown = ...
// .suspend = ... // .suspend = ...
// .resume = ... // .resume = ...
......
...@@ -224,6 +224,7 @@ ...@@ -224,6 +224,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -669,7 +670,6 @@ struct fsg_dev { ...@@ -669,7 +670,6 @@ struct fsg_dev {
wait_queue_head_t thread_wqh; wait_queue_head_t thread_wqh;
int thread_wakeup_needed; int thread_wakeup_needed;
struct completion thread_notifier; struct completion thread_notifier;
int thread_pid;
struct task_struct *thread_task; struct task_struct *thread_task;
sigset_t thread_signal_mask; sigset_t thread_signal_mask;
...@@ -1084,7 +1084,6 @@ static void wakeup_thread(struct fsg_dev *fsg) ...@@ -1084,7 +1084,6 @@ static void wakeup_thread(struct fsg_dev *fsg)
static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
{ {
unsigned long flags; unsigned long flags;
struct task_struct *thread_task;
/* Do nothing if a higher-priority exception is already in progress. /* Do nothing if a higher-priority exception is already in progress.
* If a lower-or-equal priority exception is in progress, preempt it * If a lower-or-equal priority exception is in progress, preempt it
...@@ -1093,9 +1092,9 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) ...@@ -1093,9 +1092,9 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
if (fsg->state <= new_state) { if (fsg->state <= new_state) {
fsg->exception_req_tag = fsg->ep0_req_tag; fsg->exception_req_tag = fsg->ep0_req_tag;
fsg->state = new_state; fsg->state = new_state;
thread_task = fsg->thread_task; if (fsg->thread_task)
if (thread_task) send_sig_info(SIGUSR1, SEND_SIG_FORCED,
send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task); fsg->thread_task);
} }
spin_unlock_irqrestore(&fsg->lock, flags); spin_unlock_irqrestore(&fsg->lock, flags);
} }
...@@ -3383,11 +3382,6 @@ static int fsg_main_thread(void *fsg_) ...@@ -3383,11 +3382,6 @@ static int fsg_main_thread(void *fsg_)
{ {
struct fsg_dev *fsg = (struct fsg_dev *) fsg_; struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
fsg->thread_task = current;
/* Release all our userspace resources */
daemonize("file-storage-gadget");
/* Allow the thread to be killed by a signal, but set the signal mask /* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */ * to block everything but INT, TERM, KILL, and USR1. */
siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
...@@ -3400,9 +3394,6 @@ static int fsg_main_thread(void *fsg_) ...@@ -3400,9 +3394,6 @@ static int fsg_main_thread(void *fsg_)
* that expects a __user pointer and it will work okay. */ * that expects a __user pointer and it will work okay. */
set_fs(get_ds()); set_fs(get_ds());
/* Wait for the gadget registration to finish up */
wait_for_completion(&fsg->thread_notifier);
/* The main loop */ /* The main loop */
while (fsg->state != FSG_STATE_TERMINATED) { while (fsg->state != FSG_STATE_TERMINATED) {
if (exception_in_progress(fsg) || signal_pending(current)) { if (exception_in_progress(fsg) || signal_pending(current)) {
...@@ -3440,8 +3431,9 @@ static int fsg_main_thread(void *fsg_) ...@@ -3440,8 +3431,9 @@ static int fsg_main_thread(void *fsg_)
spin_unlock_irq(&fsg->lock); spin_unlock_irq(&fsg->lock);
} }
spin_lock_irq(&fsg->lock);
fsg->thread_task = NULL; fsg->thread_task = NULL;
flush_signals(current); spin_unlock_irq(&fsg->lock);
/* In case we are exiting because of a signal, unregister the /* In case we are exiting because of a signal, unregister the
* gadget driver and close the backing file. */ * gadget driver and close the backing file. */
...@@ -3831,12 +3823,11 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3831,12 +3823,11 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Create the LUNs, open their backing files, and register the /* Create the LUNs, open their backing files, and register the
* LUN devices in sysfs. */ * LUN devices in sysfs. */
fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL);
if (!fsg->luns) { if (!fsg->luns) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
memset(fsg->luns, 0, i * sizeof(struct lun));
fsg->nluns = i; fsg->nluns = i;
for (i = 0; i < fsg->nluns; ++i) { for (i = 0; i < fsg->nluns; ++i) {
...@@ -3959,10 +3950,12 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3959,10 +3950,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
sprintf(&serial[i], "%02X", c); sprintf(&serial[i], "%02X", c);
} }
if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS | fsg->thread_task = kthread_create(fsg_main_thread, fsg,
CLONE_FILES))) < 0) "file-storage-gadget");
if (IS_ERR(fsg->thread_task)) {
rc = PTR_ERR(fsg->thread_task);
goto out; goto out;
fsg->thread_pid = rc; }
INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
...@@ -3994,7 +3987,12 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3994,7 +3987,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
mod_data.removable, mod_data.can_stall, mod_data.removable, mod_data.can_stall,
mod_data.buflen); mod_data.buflen);
DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid);
set_bit(REGISTERED, &fsg->atomic_bitflags);
/* Tell the thread to start working */
wake_up_process(fsg->thread_task);
return 0; return 0;
autoconf_fail: autoconf_fail:
...@@ -4046,6 +4044,7 @@ static struct usb_gadget_driver fsg_driver = { ...@@ -4046,6 +4044,7 @@ static struct usb_gadget_driver fsg_driver = {
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
.owner = THIS_MODULE,
// .release = ... // .release = ...
// .suspend = ... // .suspend = ...
// .resume = ... // .resume = ...
...@@ -4057,10 +4056,9 @@ static int __init fsg_alloc(void) ...@@ -4057,10 +4056,9 @@ static int __init fsg_alloc(void)
{ {
struct fsg_dev *fsg; struct fsg_dev *fsg;
fsg = kmalloc(sizeof *fsg, GFP_KERNEL); fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
if (!fsg) if (!fsg)
return -ENOMEM; return -ENOMEM;
memset(fsg, 0, sizeof *fsg);
spin_lock_init(&fsg->lock); spin_lock_init(&fsg->lock);
init_rwsem(&fsg->filesem); init_rwsem(&fsg->filesem);
init_waitqueue_head(&fsg->thread_wqh); init_waitqueue_head(&fsg->thread_wqh);
...@@ -4086,15 +4084,9 @@ static int __init fsg_init(void) ...@@ -4086,15 +4084,9 @@ static int __init fsg_init(void)
if ((rc = fsg_alloc()) != 0) if ((rc = fsg_alloc()) != 0)
return rc; return rc;
fsg = the_fsg; fsg = the_fsg;
if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) { if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
fsg_free(fsg); fsg_free(fsg);
return rc; return rc;
}
set_bit(REGISTERED, &fsg->atomic_bitflags);
/* Tell the thread to start working */
complete(&fsg->thread_notifier);
return 0;
} }
module_init(fsg_init); module_init(fsg_init);
......
...@@ -1970,6 +1970,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); ...@@ -1970,6 +1970,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
static struct pci_driver goku_pci_driver = { static struct pci_driver goku_pci_driver = {
.name = (char *) driver_name, .name = (char *) driver_name,
.id_table = pci_ids, .id_table = pci_ids,
.owner = THIS_MODULE,
.probe = goku_probe, .probe = goku_probe,
.remove = goku_remove, .remove = goku_remove,
......
...@@ -2140,6 +2140,7 @@ static int lh7a40x_udc_remove(struct device *_dev) ...@@ -2140,6 +2140,7 @@ static int lh7a40x_udc_remove(struct device *_dev)
static struct device_driver udc_driver = { static struct device_driver udc_driver = {
.name = (char *)driver_name, .name = (char *)driver_name,
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = lh7a40x_udc_probe, .probe = lh7a40x_udc_probe,
.remove = lh7a40x_udc_remove .remove = lh7a40x_udc_remove
......
...@@ -2948,6 +2948,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids); ...@@ -2948,6 +2948,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
static struct pci_driver net2280_pci_driver = { static struct pci_driver net2280_pci_driver = {
.name = (char *) driver_name, .name = (char *) driver_name,
.id_table = pci_ids, .id_table = pci_ids,
.owner = THIS_MODULE,
.probe = net2280_probe, .probe = net2280_probe,
.remove = net2280_remove, .remove = net2280_remove,
......
This diff is collapsed.
...@@ -2631,6 +2631,7 @@ static int pxa2xx_udc_resume(struct device *dev) ...@@ -2631,6 +2631,7 @@ static int pxa2xx_udc_resume(struct device *dev)
static struct device_driver udc_driver = { static struct device_driver udc_driver = {
.name = "pxa2xx-udc", .name = "pxa2xx-udc",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = pxa2xx_udc_probe, .probe = pxa2xx_udc_probe,
.shutdown = pxa2xx_udc_shutdown, .shutdown = pxa2xx_udc_shutdown,
......
...@@ -1302,6 +1302,7 @@ static struct usb_gadget_driver zero_driver = { ...@@ -1302,6 +1302,7 @@ static struct usb_gadget_driver zero_driver = {
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
.owner = THIS_MODULE,
// .shutdown = ... // .shutdown = ...
// .suspend = ... // .suspend = ...
// .resume = ... // .resume = ...
......
# #
# Makefile for USB Host Controller Driver # Makefile for USB Host Controller Drivers
# framework and drivers
# #
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -97,6 +97,7 @@ struct ehci_hcd { /* one per controller */ ...@@ -97,6 +97,7 @@ struct ehci_hcd { /* one per controller */
#else #else
# define COUNT(x) do {} while (0) # define COUNT(x) do {} while (0)
#endif #endif
u8 sbrn; /* packed release number */
}; };
/* convert between an HCD pointer and the corresponding EHCI_HCD */ /* convert between an HCD pointer and the corresponding EHCI_HCD */
......
This diff is collapsed.
...@@ -253,7 +253,6 @@ static const int cc_to_error[16] = { ...@@ -253,7 +253,6 @@ static const int cc_to_error[16] = {
struct isp116x { struct isp116x {
spinlock_t lock; spinlock_t lock;
struct work_struct rh_resume;
void __iomem *addr_reg; void __iomem *addr_reg;
void __iomem *data_reg; void __iomem *data_reg;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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