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

This commit is contained in:
Linus Torvalds 2005-10-28 21:08:14 -07:00
Родитель 974f7bc578 4303fc6f05
Коммит 1f419cadff
143 изменённых файлов: 4205 добавлений и 4596 удалений

Просмотреть файл

@ -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
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
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
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.
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
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
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
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 @@
# 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);
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)
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)
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)
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);
* 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)
} }
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)
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)
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,
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 @@
* *
* 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)
} }
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)
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/
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/
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
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 @@
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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -827,11 +827,10 @@ skip_normal_probe:
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 = {
}; };
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
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 @@
# #
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)
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,
} }
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,
} }
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)
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)
} }
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)

Просмотреть файл

@ -46,6 +46,7 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usbdevice_fs.h> #include <linux/usbdevice_fs.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/notifier.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
@ -209,10 +210,10 @@ err:
static struct async *alloc_async(unsigned int numisoframes) static struct async *alloc_async(unsigned int numisoframes)
{ {
unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor); unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
struct async *as = kmalloc(assize, GFP_KERNEL); struct async *as = kzalloc(assize, GFP_KERNEL);
if (!as) if (!as)
return NULL; return NULL;
memset(as, 0, assize);
as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
if (!as->urb) { if (!as->urb) {
kfree(as); kfree(as);
@ -279,6 +280,28 @@ static inline struct async *async_getpending(struct dev_state *ps, void __user *
return NULL; return NULL;
} }
static void snoop_urb(struct urb *urb, void __user *userurb)
{
int j;
unsigned char *data = urb->transfer_buffer;
if (!usbfs_snoop)
return;
if (urb->pipe & USB_DIR_IN)
dev_info(&urb->dev->dev, "direction=IN\n");
else
dev_info(&urb->dev->dev, "direction=OUT\n");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
dev_info(&urb->dev->dev, "data: ");
for (j = 0; j < urb->transfer_buffer_length; ++j)
printk ("%02x ", data[j]);
printk("\n");
}
static void async_completed(struct urb *urb, struct pt_regs *regs) static void async_completed(struct urb *urb, struct pt_regs *regs)
{ {
struct async *as = (struct async *)urb->context; struct async *as = (struct async *)urb->context;
@ -296,7 +319,9 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
as->euid); as->euid);
} }
wake_up(&ps->wait); snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb);
wake_up(&ps->wait);
} }
static void destroy_async (struct dev_state *ps, struct list_head *list) static void destroy_async (struct dev_state *ps, struct list_head *list)
@ -493,6 +518,23 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
return ret; return ret;
} }
static struct usb_device *usbdev_lookup_minor(int minor)
{
struct class_device *class_dev;
struct usb_device *dev = NULL;
down(&usb_device_class->sem);
list_for_each_entry(class_dev, &usb_device_class->children, node) {
if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
dev = class_dev->class_data;
break;
}
}
up(&usb_device_class->sem);
return dev;
};
/* /*
* file operations * file operations
*/ */
@ -601,7 +643,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (usbfs_snoop) { if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data "); dev_info(&dev->dev, "control read: data ");
for (j = 0; j < i; ++j) for (j = 0; j < i; ++j)
printk ("%02x ", (unsigned char)(tbuf)[j]); printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n"); printk("\n");
} }
if (copy_to_user(ctrl.data, tbuf, i)) { if (copy_to_user(ctrl.data, tbuf, i)) {
@ -624,7 +666,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (usbfs_snoop) { if (usbfs_snoop) {
dev_info(&dev->dev, "control write: data: "); dev_info(&dev->dev, "control write: data: ");
for (j = 0; j < ctrl.wLength; ++j) for (j = 0; j < ctrl.wLength; ++j)
printk ("%02x ", (unsigned char)(tbuf)[j]); printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n"); printk("\n");
} }
usb_unlock_device(dev); usb_unlock_device(dev);
@ -649,7 +691,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
unsigned int tmo, len1, pipe; unsigned int tmo, len1, pipe;
int len2; int len2;
unsigned char *tbuf; unsigned char *tbuf;
int i, ret; int i, j, ret;
if (copy_from_user(&bulk, arg, sizeof(bulk))) if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT; return -EFAULT;
@ -674,10 +716,18 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf); kfree(tbuf);
return -EINVAL; return -EINVAL;
} }
snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
bulk.len, bulk.timeout);
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev); usb_lock_device(dev);
if (!i && len2) { if (!i && len2) {
if (usbfs_snoop) {
dev_info(&dev->dev, "bulk read: data ");
for (j = 0; j < len2; ++j)
printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
if (copy_to_user(bulk.data, tbuf, len2)) { if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf); kfree(tbuf);
return -EFAULT; return -EFAULT;
@ -690,6 +740,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT; return -EFAULT;
} }
} }
snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n",
bulk.len, bulk.timeout);
if (usbfs_snoop) {
dev_info(&dev->dev, "bulk write: data: ");
for (j = 0; j < len1; ++j)
printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev); usb_lock_device(dev);
@ -835,7 +893,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
return status; return status;
} }
static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc, struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg) void __user *arg)
@ -896,6 +953,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr); kfree(dr);
return -EFAULT; return -EFAULT;
} }
snoop(&ps->dev->dev, "control urb\n");
break; break;
case USBDEVFS_URB_TYPE_BULK: case USBDEVFS_URB_TYPE_BULK:
@ -910,6 +968,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL; return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT; return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break; break;
case USBDEVFS_URB_TYPE_ISO: case USBDEVFS_URB_TYPE_ISO:
@ -939,6 +998,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL; return -EINVAL;
} }
uurb->buffer_length = totlen; uurb->buffer_length = totlen;
snoop(&ps->dev->dev, "iso urb\n");
break; break;
case USBDEVFS_URB_TYPE_INTERRUPT: case USBDEVFS_URB_TYPE_INTERRUPT:
@ -954,6 +1014,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL; return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
return -EFAULT; return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break; break;
default: default:
@ -1003,6 +1064,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EFAULT; return -EFAULT;
} }
} }
snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as); async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret); dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
@ -1238,23 +1301,20 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
return 0; return 0;
} }
static int proc_ioctl (struct dev_state *ps, void __user *arg) static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
{ {
struct usbdevfs_ioctl ctrl;
int size; int size;
void *buf = NULL; void *buf = NULL;
int retval = 0; int retval = 0;
struct usb_interface *intf = NULL; struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL; struct usb_driver *driver = NULL;
/* get input parameters and alloc buffer */ /* alloc buffer */
if (copy_from_user(&ctrl, arg, sizeof (ctrl))) if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) {
return -EFAULT;
if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
if (copy_from_user (buf, ctrl.data, size)) { if (copy_from_user (buf, ctl->data, size)) {
kfree(buf); kfree(buf);
return -EFAULT; return -EFAULT;
} }
@ -1270,9 +1330,9 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
if (ps->dev->state != USB_STATE_CONFIGURED) if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -EHOSTUNREACH; retval = -EHOSTUNREACH;
else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno))) else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno)))
retval = -EINVAL; retval = -EINVAL;
else switch (ctrl.ioctl_code) { else switch (ctl->ioctl_code) {
/* disconnect kernel driver from interface */ /* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT: case USBDEVFS_DISCONNECT:
@ -1304,7 +1364,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
if (driver == NULL || driver->ioctl == NULL) { if (driver == NULL || driver->ioctl == NULL) {
retval = -ENOTTY; retval = -ENOTTY;
} else { } else {
retval = driver->ioctl (intf, ctrl.ioctl_code, buf); retval = driver->ioctl (intf, ctl->ioctl_code, buf);
if (retval == -ENOIOCTLCMD) if (retval == -ENOIOCTLCMD)
retval = -ENOTTY; retval = -ENOTTY;
} }
@ -1313,15 +1373,42 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
/* cleanup and return */ /* cleanup and return */
if (retval >= 0 if (retval >= 0
&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0 && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
&& size > 0 && size > 0
&& copy_to_user (ctrl.data, buf, size) != 0) && copy_to_user (ctl->data, buf, size) != 0)
retval = -EFAULT; retval = -EFAULT;
kfree(buf); kfree(buf);
return retval; return retval;
} }
static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_ioctl ctrl;
if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
return -EFAULT;
return proc_ioctl(ps, &ctrl);
}
#ifdef CONFIG_COMPAT
static int proc_ioctl_compat(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_ioctl32 __user *uioc;
struct usbdevfs_ioctl ctrl;
u32 udata;
uioc = compat_ptr(arg);
if (get_user(ctrl.ifno, &uioc->ifno) ||
get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
__get_user(udata, &uioc->data))
return -EFAULT;
ctrl.data = compat_ptr(udata);
return proc_ioctl(ps, &ctrl);
}
#endif
/* /*
* NOTE: All requests here that have interface numbers as parameters * NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from * are assuming that somehow the configuration has been prevented from
@ -1422,6 +1509,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
ret = proc_reapurbnonblock_compat(ps, p); ret = proc_reapurbnonblock_compat(ps, p);
break; break;
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
ret = proc_ioctl_compat(ps, p);
break;
#endif #endif
case USBDEVFS_DISCARDURB: case USBDEVFS_DISCARDURB:
@ -1456,7 +1547,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case USBDEVFS_IOCTL: case USBDEVFS_IOCTL:
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
ret = proc_ioctl(ps, p); ret = proc_ioctl_default(ps, p);
break; break;
} }
usb_unlock_device(dev); usb_unlock_device(dev);
@ -1488,24 +1579,7 @@ struct file_operations usbfs_device_file_operations = {
.release = usbdev_release, .release = usbdev_release,
}; };
struct usb_device *usbdev_lookup_minor(int minor) static void usbdev_add(struct usb_device *dev)
{
struct class_device *class_dev;
struct usb_device *dev = NULL;
down(&usb_device_class->sem);
list_for_each_entry(class_dev, &usb_device_class->children, node) {
if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
dev = class_dev->class_data;
break;
}
}
up(&usb_device_class->sem);
return dev;
};
void usbdev_add(struct usb_device *dev)
{ {
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
@ -1516,11 +1590,29 @@ void usbdev_add(struct usb_device *dev)
dev->class_dev->class_data = dev; dev->class_dev->class_data = dev;
} }
void usbdev_remove(struct usb_device *dev) static void usbdev_remove(struct usb_device *dev)
{ {
class_device_unregister(dev->class_dev); class_device_unregister(dev->class_dev);
} }
static int usbdev_notify(struct notifier_block *self, unsigned long action,
void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
usbdev_add(dev);
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
break;
}
return NOTIFY_OK;
}
static struct notifier_block usbdev_nb = {
.notifier_call = usbdev_notify,
};
static struct cdev usb_device_cdev = { static struct cdev usb_device_cdev = {
.kobj = {.name = "usb_device", }, .kobj = {.name = "usb_device", },
.owner = THIS_MODULE, .owner = THIS_MODULE,
@ -1540,24 +1632,32 @@ int __init usbdev_init(void)
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) { if (retval) {
err("unable to get usb_device major %d", USB_DEVICE_MAJOR); err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); goto error_cdev;
goto out;
} }
usb_device_class = class_create(THIS_MODULE, "usb_device"); usb_device_class = class_create(THIS_MODULE, "usb_device");
if (IS_ERR(usb_device_class)) { if (IS_ERR(usb_device_class)) {
err("unable to register usb_device class"); err("unable to register usb_device class");
retval = PTR_ERR(usb_device_class); retval = PTR_ERR(usb_device_class);
usb_device_class = NULL; goto error_class;
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
} }
usb_register_notify(&usbdev_nb);
out: out:
return retval; return retval;
error_class:
usb_device_class = NULL;
cdev_del(&usb_device_cdev);
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
} }
void usbdev_cleanup(void) void usbdev_cleanup(void)
{ {
usb_unregister_notify(&usbdev_nb);
class_destroy(usb_device_class); class_destroy(usb_device_class);
cdev_del(&usb_device_cdev); cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);

Просмотреть файл

@ -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)
goto out; goto out;
} }
devfs_mk_dir("usb");
out: out:
return error; return error;
} }
@ -97,7 +94,6 @@ out:
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)
* 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,
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,
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,9 +188,8 @@ 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.
*/ */
void usb_deregister_dev(struct usb_interface *intf, 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 @@
#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)
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)
*/ */
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)
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)
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)
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)
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,
usb_hc_died (hcd); "PCI post-resume error %d!\n", retval);
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] = {
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] = {
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,22 +458,18 @@ 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)) switch (typeReq) {
status = -EAGAIN; case GetHubStatus:
else { case GetPortStatus:
switch (typeReq) { len = 4;
case GetHubStatus: break;
case GetPortStatus: case GetHubDescriptor:
len = 4; len = sizeof (struct usb_hub_descriptor);
break; break;
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
}
status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
tbuf, wLength);
} }
status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
tbuf, wLength);
break; break;
error: error:
/* "protocol stall" on error */ /* "protocol stall" on error */
@ -487,7 +483,7 @@ error:
"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)
{ {
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)
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)
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)
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)
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 @@ rescan:
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#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;
return 0; if (hcd->state == HC_STATE_RUNNING)
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)
* 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,14 +1532,10 @@ 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);
} }
#else
void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
{
}
#endif
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
#endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_OTG #ifdef CONFIG_USB_OTG
@ -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 {
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 {
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 {
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,
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,
#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,
* 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 {
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;
@ -443,18 +452,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
if (bus->monitored) if (bus->monitored)
(*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) {}
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 */

Просмотреть файл

@ -436,9 +436,10 @@ static void hub_power_on(struct usb_hub *hub)
{ {
int port1; int port1;
unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
/* if hub supports power switching, enable power on each port */ /* if hub supports power switching, enable power on each port */
if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
dev_dbg(hub->intfdev, "enabling power on all ports\n"); dev_dbg(hub->intfdev, "enabling power on all ports\n");
for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
set_port_feature(hub->hdev, port1, set_port_feature(hub->hdev, port1,
@ -449,10 +450,18 @@ static void hub_power_on(struct usb_hub *hub)
msleep(max(pgood_delay, (unsigned) 100)); msleep(max(pgood_delay, (unsigned) 100));
} }
static inline void __hub_quiesce(struct usb_hub *hub)
{
/* (nonblocking) khubd and related activity won't re-trigger */
hub->quiescing = 1;
hub->activating = 0;
hub->resume_root_hub = 0;
}
static void hub_quiesce(struct usb_hub *hub) static void hub_quiesce(struct usb_hub *hub)
{ {
/* stop khubd and related activity */ /* (blocking) stop khubd and related activity */
hub->quiescing = 1; __hub_quiesce(hub);
usb_kill_urb(hub->urb); usb_kill_urb(hub->urb);
if (hub->has_indicators) if (hub->has_indicators)
cancel_delayed_work(&hub->leds); cancel_delayed_work(&hub->leds);
@ -466,6 +475,7 @@ static void hub_activate(struct usb_hub *hub)
hub->quiescing = 0; hub->quiescing = 0;
hub->activating = 1; hub->activating = 1;
hub->resume_root_hub = 0;
status = usb_submit_urb(hub->urb, GFP_NOIO); status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0) if (status < 0)
dev_err(hub->intfdev, "activate --> %d\n", status); dev_err(hub->intfdev, "activate --> %d\n", status);
@ -516,6 +526,7 @@ static int hub_configure(struct usb_hub *hub,
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev; struct device *hub_dev = hub->intfdev;
u16 hubstatus, hubchange; u16 hubstatus, hubchange;
u16 wHubCharacteristics;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
char *message; char *message;
@ -561,9 +572,9 @@ static int hub_configure(struct usb_hub *hub,
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s"); (hdev->maxchild == 1) ? "" : "s");
le16_to_cpus(&hub->descriptor->wHubCharacteristics); wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) { if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
int i; int i;
char portstr [USB_MAXCHILDREN + 1]; char portstr [USB_MAXCHILDREN + 1];
@ -576,7 +587,7 @@ static int hub_configure(struct usb_hub *hub,
} else } else
dev_dbg(hub_dev, "standalone hub\n"); dev_dbg(hub_dev, "standalone hub\n");
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { switch (wHubCharacteristics & HUB_CHAR_LPSM) {
case 0x00: case 0x00:
dev_dbg(hub_dev, "ganged power switching\n"); dev_dbg(hub_dev, "ganged power switching\n");
break; break;
@ -589,7 +600,7 @@ static int hub_configure(struct usb_hub *hub,
break; break;
} }
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { switch (wHubCharacteristics & HUB_CHAR_OCPM) {
case 0x00: case 0x00:
dev_dbg(hub_dev, "global over-current protection\n"); dev_dbg(hub_dev, "global over-current protection\n");
break; break;
@ -629,7 +640,7 @@ static int hub_configure(struct usb_hub *hub,
} }
/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { switch (wHubCharacteristics & HUB_CHAR_TTTT) {
case HUB_TTTT_8_BITS: case HUB_TTTT_8_BITS:
if (hdev->descriptor.bDeviceProtocol != 0) { if (hdev->descriptor.bDeviceProtocol != 0) {
hub->tt.think_time = 666; hub->tt.think_time = 666;
@ -659,7 +670,7 @@ static int hub_configure(struct usb_hub *hub,
} }
/* probe() zeroes hub->indicator[] */ /* probe() zeroes hub->indicator[] */
if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) { if (wHubCharacteristics & HUB_CHAR_PORTIND) {
hub->has_indicators = 1; hub->has_indicators = 1;
dev_dbg(hub_dev, "Port indicators are supported\n"); dev_dbg(hub_dev, "Port indicators are supported\n");
} }
@ -704,7 +715,7 @@ static int hub_configure(struct usb_hub *hub,
(hubstatus & HUB_STATUS_LOCAL_POWER) (hubstatus & HUB_STATUS_LOCAL_POWER)
? "lost (inactive)" : "good"); ? "lost (inactive)" : "good");
if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0) if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
dev_dbg(hub_dev, "%sover-current condition exists\n", dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
@ -854,14 +865,12 @@ descriptor_error:
/* We found a hub */ /* We found a hub */
dev_info (&intf->dev, "USB hub found\n"); dev_info (&intf->dev, "USB hub found\n");
hub = kmalloc(sizeof(*hub), GFP_KERNEL); hub = kzalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) { if (!hub) {
dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
return -ENOMEM; return -ENOMEM;
} }
memset(hub, 0, sizeof(*hub));
INIT_LIST_HEAD(&hub->event_list); INIT_LIST_HEAD(&hub->event_list);
hub->intfdev = &intf->dev; hub->intfdev = &intf->dev;
hub->hdev = hdev; hub->hdev = hdev;
@ -1117,14 +1126,14 @@ void usb_disconnect(struct usb_device **pdev)
*/ */
usb_disable_device(udev, 0); usb_disable_device(udev, 0);
usb_notify_remove_device(udev);
/* Free the device number, remove the /proc/bus/usb entry and /* Free the device number, remove the /proc/bus/usb entry and
* the sysfs attributes, and delete the parent's children[] * the sysfs attributes, and delete the parent's children[]
* (or root_hub) pointer. * (or root_hub) pointer.
*/ */
dev_dbg (&udev->dev, "unregistering device\n"); dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev); release_address(udev);
usbfs_remove_device(udev);
usbdev_remove(udev);
usb_remove_sysfs_dev_files(udev); usb_remove_sysfs_dev_files(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */ /* Avoid races with recursively_mark_NOTATTACHED() */
@ -1195,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
{} {}
#endif #endif
static void get_string(struct usb_device *udev, char **string, int index)
{
char *buf;
if (!index)
return;
buf = kmalloc(256, GFP_KERNEL);
if (!buf)
return;
if (usb_string(udev, index, buf, 256) > 0)
*string = buf;
else
kfree(buf);
}
#ifdef CONFIG_USB_OTG #ifdef CONFIG_USB_OTG
#include "otg_whitelist.h" #include "otg_whitelist.h"
@ -1248,9 +1242,10 @@ int usb_new_device(struct usb_device *udev)
} }
/* read the standard strings and cache them if present */ /* read the standard strings and cache them if present */
get_string(udev, &udev->product, udev->descriptor.iProduct); udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer); udev->manufacturer = usb_cache_string(udev,
get_string(udev, &udev->serial, udev->descriptor.iSerialNumber); udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
/* Tell the world! */ /* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, " dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
@ -1322,11 +1317,9 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.) * (Includes HNP test device.)
*/ */
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
static int __usb_suspend_device (struct usb_device *, static int __usb_suspend_device(struct usb_device *,
int port1, pm_message_t state); int port1);
err = __usb_suspend_device(udev, err = __usb_suspend_device(udev, udev->bus->otg_port);
udev->bus->otg_port,
PMSG_SUSPEND);
if (err < 0) if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err); dev_dbg(&udev->dev, "HNP fail, %d\n", err);
} }
@ -1362,10 +1355,8 @@ int usb_new_device(struct usb_device *udev)
} }
/* USB device state == configured ... usable */ /* USB device state == configured ... usable */
usb_notify_add_device(udev);
/* add a /proc/bus/usb entry */
usbdev_add(udev);
usbfs_add_device(udev);
return 0; return 0;
fail: fail:
@ -1516,7 +1507,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
/* FIXME let caller ask to power down the port: /* FIXME let caller ask to power down the port:
* - some devices won't enumerate without a VBUS power cycle * - some devices won't enumerate without a VBUS power cycle
* - SRP saves power that way * - SRP saves power that way
* - usb_suspend_device(dev, PMSG_SUSPEND) * - ... new call, TBD ...
* That's easy if this hub can switch power per-port, and * That's easy if this hub can switch power per-port, and
* khubd reactivates the port later (timer, SRP, etc). * khubd reactivates the port later (timer, SRP, etc).
* Powerdown must be optional, because of reset/DFU. * Powerdown must be optional, because of reset/DFU.
@ -1598,11 +1589,14 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* Other than re-initializing the hub (plug/unplug, except for root hubs), * Other than re-initializing the hub (plug/unplug, except for root hubs),
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd * Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs. * timer, no SRP, no requests through sysfs.
*
* If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*/ */
static int __usb_suspend_device (struct usb_device *udev, int port1, static int __usb_suspend_device (struct usb_device *udev, int port1)
pm_message_t state)
{ {
int status; int status = 0;
/* caller owns the udev device lock */ /* caller owns the udev device lock */
if (port1 < 0) if (port1 < 0)
@ -1613,95 +1607,39 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
return 0; return 0;
} }
/* suspend interface drivers; if this is a hub, it /* all interfaces must already be suspended */
* suspends the child devices
*/
if (udev->actconfig) { if (udev->actconfig) {
int i; int i;
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_driver *driver;
intf = udev->actconfig->interface[i]; intf = udev->actconfig->interface[i];
if (state.event <= intf->dev.power.power_state.event) if (is_active(intf)) {
continue; dev_dbg(&intf->dev, "nyet suspended\n");
if (!intf->dev.driver) return -EBUSY;
continue;
driver = to_usb_driver(intf->dev.driver);
if (driver->suspend) {
status = driver->suspend(intf, state);
if (intf->dev.power.power_state.event != state.event
|| status)
dev_err(&intf->dev,
"suspend %d fail, code %d\n",
state.event, status);
}
/* only drivers with suspend() can ever resume();
* and after power loss, even they won't.
* bus_rescan_devices() can rebind drivers later.
*
* FIXME the PM core self-deadlocks when unbinding
* drivers during suspend/resume ... everything grabs
* dpm_sem (not a spinlock, ugh). we want to unbind,
* since we know every driver's probe/disconnect works
* even for drivers that can't suspend.
*/
if (!driver->suspend || state.event > PM_EVENT_FREEZE) {
#if 1
dev_warn(&intf->dev, "resume is unsafe!\n");
#else
down_write(&usb_bus_type.rwsem);
device_release_driver(&intf->dev);
up_write(&usb_bus_type.rwsem);
#endif
} }
} }
} }
/* /* we only change a device's upstream USB link.
* FIXME this needs port power off call paths too, to help force * root hubs have no upstream USB link.
* USB into the "generic" PM model. At least for devices on
* ports that aren't using ganged switching (usually root hubs).
*
* NOTE: SRP-capable links should adopt more aggressive poweroff
* policies (when HNP doesn't apply) once we have mechanisms to
* turn power back on! (Likely not before 2.7...)
*/ */
if (state.event > PM_EVENT_FREEZE) { if (udev->parent)
dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
}
/* "global suspend" of the HC-to-USB interface (root hub), or
* "selective suspend" of just one hub-device link.
*/
if (!udev->parent) {
struct usb_bus *bus = udev->bus;
if (bus && bus->op->hub_suspend) {
status = bus->op->hub_suspend (bus);
if (status == 0) {
dev_dbg(&udev->dev, "usb suspend\n");
usb_set_device_state(udev,
USB_STATE_SUSPENDED);
}
} else
status = -EOPNOTSUPP;
} else
status = hub_port_suspend(hdev_to_hub(udev->parent), port1, status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
udev); udev);
if (status == 0) if (status == 0)
udev->dev.power.power_state = state; udev->dev.power.power_state = PMSG_SUSPEND;
return status; return status;
} }
/** #endif
/*
* usb_suspend_device - suspend a usb device * usb_suspend_device - suspend a usb device
* @udev: device that's no longer in active use * @udev: device that's no longer in active use
* @state: PMSG_SUSPEND to suspend * Context: must be able to sleep; device not locked; pm locks held
* Context: must be able to sleep; device not locked
* *
* Suspends a USB device that isn't in active use, conserving power. * Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens, * Devices may wake out of a suspend, if anything important happens,
@ -1709,37 +1647,50 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
* suspend by the host, using usb_resume_device(). It's also routine * suspend by the host, using usb_resume_device(). It's also routine
* to disconnect devices while they are suspended. * to disconnect devices while they are suspended.
* *
* This only affects the USB hardware for a device; its interfaces
* (and, for hubs, child devices) must already have been suspended.
*
* Suspending OTG devices may trigger HNP, if that's been enabled * Suspending OTG devices may trigger HNP, if that's been enabled
* between a pair of dual-role devices. That will change roles, such * between a pair of dual-role devices. That will change roles, such
* as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
* *
* Returns 0 on success, else negative errno. * Returns 0 on success, else negative errno.
*/ */
int usb_suspend_device(struct usb_device *udev, pm_message_t state) int usb_suspend_device(struct usb_device *udev)
{ {
#ifdef CONFIG_USB_SUSPEND
int port1, status; int port1, status;
port1 = locktree(udev); port1 = locktree(udev);
if (port1 < 0) if (port1 < 0)
return port1; return port1;
status = __usb_suspend_device(udev, port1, state); status = __usb_suspend_device(udev, port1);
usb_unlock_device(udev); usb_unlock_device(udev);
return status; return status;
#else
/* NOTE: udev->state unchanged, it's not lying ... */
udev->dev.power.power_state = PMSG_SUSPEND;
return 0;
#endif
} }
EXPORT_SYMBOL_GPL(usb_suspend_device);
/* /*
* If the USB "suspend" state is in use (rather than "global suspend"),
* many devices will be individually taken out of suspend state using
* special" resume" signaling. These routines kick in shortly after
* hardware resume signaling is finished, either because of selective * hardware resume signaling is finished, either because of selective
* resume (by host) or remote wakeup (by device) ... now see what changed * resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device. * in the tree that's rooted at this device.
*/ */
static int finish_port_resume(struct usb_device *udev) static int finish_device_resume(struct usb_device *udev)
{ {
int status; int status;
u16 devstatus; u16 devstatus;
/* caller owns the udev device lock */ /* caller owns the udev device lock */
dev_dbg(&udev->dev, "usb resume\n"); dev_dbg(&udev->dev, "finish resume\n");
/* usb ch9 identifies four variants of SUSPENDED, based on what /* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the * state the device resumes to. Linux currently won't see the
@ -1749,7 +1700,6 @@ static int finish_port_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED ? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS); : USB_STATE_ADDRESS);
udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there. /* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume, * For now let's assume the device didn't go crazy on resume,
@ -1762,9 +1712,11 @@ static int finish_port_resume(struct usb_device *udev)
status); status);
else if (udev->actconfig) { else if (udev->actconfig) {
unsigned i; unsigned i;
int (*resume)(struct device *);
le16_to_cpus(&devstatus); le16_to_cpus(&devstatus);
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)
&& udev->parent) {
status = usb_control_msg(udev, status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0), usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_REQ_CLEAR_FEATURE,
@ -1780,33 +1732,11 @@ static int finish_port_resume(struct usb_device *udev)
} }
/* resume interface drivers; if this is a hub, it /* resume interface drivers; if this is a hub, it
* resumes the child devices * may have a child resume event to deal with soon
*/ */
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { resume = udev->dev.bus->resume;
struct usb_interface *intf; for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
struct usb_driver *driver; (void) resume(&udev->actconfig->interface[i]->dev);
intf = udev->actconfig->interface[i];
if (intf->dev.power.power_state.event == PM_EVENT_ON)
continue;
if (!intf->dev.driver) {
/* FIXME maybe force to alt 0 */
continue;
}
driver = to_usb_driver(intf->dev.driver);
/* bus_rescan_devices() may rebind drivers */
if (!driver->resume)
continue;
/* can we do better than just logging errors? */
status = driver->resume(intf);
if (intf->dev.power.power_state.event != PM_EVENT_ON
|| status)
dev_dbg(&intf->dev,
"resume fail, state %d code %d\n",
intf->dev.power.power_state.event, status);
}
status = 0; status = 0;
} else if (udev->devnum <= 0) { } else if (udev->devnum <= 0) {
@ -1816,6 +1746,8 @@ static int finish_port_resume(struct usb_device *udev)
return status; return status;
} }
#ifdef CONFIG_USB_SUSPEND
static int static int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{ {
@ -1861,7 +1793,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* TRSMRCY = 10 msec */ /* TRSMRCY = 10 msec */
msleep(10); msleep(10);
if (udev) if (udev)
status = finish_port_resume(udev); status = finish_device_resume(udev);
} }
} }
if (status < 0) if (status < 0)
@ -1870,12 +1802,12 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
return status; return status;
} }
static int hub_resume (struct usb_interface *intf); #endif
/** /*
* usb_resume_device - re-activate a suspended usb device * usb_resume_device - re-activate a suspended usb device
* @udev: device to re-activate * @udev: device to re-activate
* Context: must be able to sleep; device not locked * Context: must be able to sleep; device not locked; pm locks held
* *
* This will re-activate the suspended device, increasing power usage * This will re-activate the suspended device, increasing power usage
* while letting drivers communicate again with its endpoints. * while letting drivers communicate again with its endpoints.
@ -1893,35 +1825,22 @@ int usb_resume_device(struct usb_device *udev)
if (port1 < 0) if (port1 < 0)
return port1; return port1;
/* "global resume" of the HC-to-USB interface (root hub), or #ifdef CONFIG_USB_SUSPEND
* selective resume of one hub-to-device port /* selective resume of one downstream hub-to-device port */
*/ if (udev->parent) {
if (!udev->parent) { if (udev->state == USB_STATE_SUSPENDED) {
struct usb_bus *bus = udev->bus; // NOTE swsusp may bork us, device state being wrong...
if (bus && bus->op->hub_resume) { // NOTE this fails if parent is also suspended...
status = bus->op->hub_resume (bus); status = hub_port_resume(hdev_to_hub(udev->parent),
port1, udev);
} else } else
status = -EOPNOTSUPP; status = 0;
if (status == 0) { } else
dev_dbg(&udev->dev, "usb resume\n"); #endif
/* TRSMRCY = 10 msec */ status = finish_device_resume(udev);
msleep(10); if (status < 0)
usb_set_device_state (udev, USB_STATE_CONFIGURED);
udev->dev.power.power_state = PMSG_ON;
status = hub_resume (udev
->actconfig->interface[0]);
}
} else if (udev->state == USB_STATE_SUSPENDED) {
// NOTE this fails if parent is also suspended...
status = hub_port_resume(hdev_to_hub(udev->parent),
port1, udev);
} else {
status = 0;
}
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", dev_dbg(&udev->dev, "can't resume, status %d\n",
status); status);
}
usb_unlock_device(udev); usb_unlock_device(udev);
@ -1938,6 +1857,8 @@ static int remote_wakeup(struct usb_device *udev)
{ {
int status = 0; int status = 0;
#ifdef CONFIG_USB_SUSPEND
/* don't repeat RESUME sequence if this device /* don't repeat RESUME sequence if this device
* was already woken up by some other task * was already woken up by some other task
*/ */
@ -1946,38 +1867,52 @@ static int remote_wakeup(struct usb_device *udev)
dev_dbg(&udev->dev, "RESUME (wakeup)\n"); dev_dbg(&udev->dev, "RESUME (wakeup)\n");
/* TRSMRCY = 10 msec */ /* TRSMRCY = 10 msec */
msleep(10); msleep(10);
status = finish_port_resume(udev); status = finish_device_resume(udev);
} }
up(&udev->serialize); up(&udev->serialize);
#endif
return status; return status;
} }
static int hub_suspend(struct usb_interface *intf, pm_message_t state) static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
{ {
struct usb_hub *hub = usb_get_intfdata (intf); struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
unsigned port1; unsigned port1;
int status;
/* stop khubd and related activity */ /* fail if children aren't already suspended */
hub_quiesce(hub);
/* then suspend every port */
for (port1 = 1; port1 <= hdev->maxchild; port1++) { for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev; struct usb_device *udev;
udev = hdev->children [port1-1]; udev = hdev->children [port1-1];
if (!udev) if (udev && (udev->dev.power.power_state.event
continue; == PM_EVENT_ON
down(&udev->serialize); #ifdef CONFIG_USB_SUSPEND
status = __usb_suspend_device(udev, port1, state); || udev->state != USB_STATE_SUSPENDED
up(&udev->serialize); #endif
if (status < 0) )) {
dev_dbg(&intf->dev, "suspend port %d --> %d\n", dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
port1, status); return -EBUSY;
}
} }
intf->dev.power.power_state = state; /* "global suspend" of the downstream HC-to-USB interface */
if (!hdev->parent) {
struct usb_bus *bus = hdev->bus;
if (bus) {
int status = hcd_bus_suspend (bus);
if (status != 0) {
dev_dbg(&hdev->dev, "'global' suspend %d\n",
status);
return status;
}
} else
return -EOPNOTSUPP;
}
/* stop khubd and related activity */
hub_quiesce(hub);
return 0; return 0;
} }
@ -1985,11 +1920,35 @@ static int hub_resume(struct usb_interface *intf)
{ {
struct usb_device *hdev = interface_to_usbdev(intf); struct usb_device *hdev = interface_to_usbdev(intf);
struct usb_hub *hub = usb_get_intfdata (intf); struct usb_hub *hub = usb_get_intfdata (intf);
unsigned port1;
int status; int status;
if (intf->dev.power.power_state.event == PM_EVENT_ON) /* "global resume" of the downstream HC-to-USB interface */
return 0; if (!hdev->parent) {
struct usb_bus *bus = hdev->bus;
if (bus) {
status = hcd_bus_resume (bus);
if (status) {
dev_dbg(&intf->dev, "'global' resume %d\n",
status);
return status;
}
} else
return -EOPNOTSUPP;
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
}
}
hub_activate(hub);
/* REVISIT: this recursion probably shouldn't exist. Remove
* this code sometime, after retesting with different root and
* external hubs.
*/
#ifdef CONFIG_USB_SUSPEND
{
unsigned port1;
for (port1 = 1; port1 <= hdev->maxchild; port1++) { for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev; struct usb_device *udev;
@ -2015,7 +1974,7 @@ static int hub_resume(struct usb_interface *intf)
if (portstat & USB_PORT_STAT_SUSPEND) if (portstat & USB_PORT_STAT_SUSPEND)
status = hub_port_resume(hub, port1, udev); status = hub_port_resume(hub, port1, udev);
else { else {
status = finish_port_resume(udev); status = finish_device_resume(udev);
if (status < 0) { if (status < 0) {
dev_dbg(&intf->dev, "resume port %d --> %d\n", dev_dbg(&intf->dev, "resume port %d --> %d\n",
port1, status); port1, status);
@ -2024,13 +1983,23 @@ static int hub_resume(struct usb_interface *intf)
} }
up(&udev->serialize); up(&udev->serialize);
} }
intf->dev.power.power_state = PMSG_ON; }
#endif
hub->resume_root_hub = 0;
hub_activate(hub);
return 0; return 0;
} }
void usb_suspend_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
/* This also makes any led blinker stop retriggering. We're called
* from irq, so the blinker might still be scheduled. Caller promises
* that the root hub status URB will be canceled.
*/
__hub_quiesce(hub);
mark_quiesced(to_usb_interface(hub->intfdev));
}
void usb_resume_root_hub(struct usb_device *hdev) void usb_resume_root_hub(struct usb_device *hdev)
{ {
struct usb_hub *hub = hdev_to_hub(hdev); struct usb_hub *hub = hdev_to_hub(hdev);
@ -2039,28 +2008,6 @@ void usb_resume_root_hub(struct usb_device *hdev)
kick_khubd(hub); kick_khubd(hub);
} }
#else /* !CONFIG_USB_SUSPEND */
int usb_suspend_device(struct usb_device *udev, pm_message_t state)
{
return 0;
}
int usb_resume_device(struct usb_device *udev)
{
return 0;
}
#define hub_suspend NULL
#define hub_resume NULL
#define remote_wakeup(x) 0
#endif /* CONFIG_USB_SUSPEND */
EXPORT_SYMBOL(usb_suspend_device);
EXPORT_SYMBOL(usb_resume_device);
/* USB 2.0 spec, 7.1.7.3 / fig 7-29: /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
* *
@ -2469,6 +2416,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
{ {
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev; struct device *hub_dev = hub->intfdev;
u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
int status, i; int status, i;
dev_dbg (hub_dev, dev_dbg (hub_dev,
@ -2506,8 +2454,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (!(portstatus & USB_PORT_STAT_CONNECTION)) { if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
/* maybe switch power back on (e.g. root hub was reset) */ /* maybe switch power back on (e.g. root hub was reset) */
if ((hub->descriptor->wHubCharacteristics if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
& HUB_CHAR_LPSM) < 2
&& !(portstatus & (1 << USB_PORT_FEAT_POWER))) && !(portstatus & (1 << USB_PORT_FEAT_POWER)))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
@ -2686,21 +2633,28 @@ static void hub_events(void)
intf = to_usb_interface(hub->intfdev); intf = to_usb_interface(hub->intfdev);
hub_dev = &intf->dev; hub_dev = &intf->dev;
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", i = hub->resume_root_hub;
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n",
hdev->state, hub->descriptor hdev->state, hub->descriptor
? hub->descriptor->bNbrPorts ? hub->descriptor->bNbrPorts
: 0, : 0,
/* NOTE: expects max 15 ports... */ /* NOTE: expects max 15 ports... */
(u16) hub->change_bits[0], (u16) hub->change_bits[0],
(u16) hub->event_bits[0]); (u16) hub->event_bits[0],
i ? ", resume root" : "");
usb_get_intf(intf); usb_get_intf(intf);
i = hub->resume_root_hub;
spin_unlock_irq(&hub_event_lock); spin_unlock_irq(&hub_event_lock);
/* Is this is a root hub wanting to be resumed? */ /* Is this is a root hub wanting to reactivate the downstream
if (i) * ports? If so, be sure the interface resumes even if its
usb_resume_device(hdev); * stub "device" node was never suspended.
*/
if (i) {
dpm_runtime_resume(&hdev->dev);
dpm_runtime_resume(&intf->dev);
}
/* Lock the device, then check to see if we were /* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */ * disconnected while waiting for the lock to succeed. */

Просмотреть файл

@ -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 @@
#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)
} }
} }
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)
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)
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)
} }
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)
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)
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)
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,21 +187,37 @@ 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;
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
usb_api_blocking_completion, NULL); 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_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length); return usb_start_wait_urb(urb, timeout, actual_length);
} }
@ -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)
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)
*/ */
/* 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)
* (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)
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)
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)
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)
} }
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 @@ free_interfaces:
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 @@ free_interfaces:
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 @@ free_interfaces:
} }
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 @@ free_interfaces:
*/ */
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 @@ free_interfaces:
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);
} }
} }

120
drivers/usb/core/notify.c Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/*
* 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);
}

Просмотреть файл

@ -22,9 +22,207 @@
#include "usb.h" #include "usb.h"
/* endpoint stuff */
struct ep_object {
struct usb_endpoint_descriptor *desc;
struct usb_device *udev;
struct kobject kobj;
};
#define to_ep_object(_kobj) \
container_of(_kobj, struct ep_object, kobj)
struct ep_attribute {
struct attribute attr;
ssize_t (*show)(struct usb_device *,
struct usb_endpoint_descriptor *, char *);
};
#define to_ep_attribute(_attr) \
container_of(_attr, struct ep_attribute, attr)
#define EP_ATTR(_name) \
struct ep_attribute ep_##_name = { \
.attr = {.name = #_name, .owner = THIS_MODULE, \
.mode = S_IRUGO}, \
.show = show_ep_##_name}
#define usb_ep_attr(field, format_string) \
static ssize_t show_ep_##field(struct usb_device *udev, \
struct usb_endpoint_descriptor *desc, \
char *buf) \
{ \
return sprintf(buf, format_string, desc->field); \
} \
static EP_ATTR(field);
usb_ep_attr(bLength, "%02x\n")
usb_ep_attr(bEndpointAddress, "%02x\n")
usb_ep_attr(bmAttributes, "%02x\n")
usb_ep_attr(bInterval, "%02x\n")
static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
return sprintf(buf, "%04x\n",
le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
}
static EP_ATTR(wMaxPacketSize);
static ssize_t show_ep_type(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char *type = "unknown";
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_CONTROL:
type = "Control";
break;
case USB_ENDPOINT_XFER_ISOC:
type = "Isoc";
break;
case USB_ENDPOINT_XFER_BULK:
type = "Bulk";
break;
case USB_ENDPOINT_XFER_INT:
type = "Interrupt";
break;
}
return sprintf(buf, "%s\n", type);
}
static EP_ATTR(type);
static ssize_t show_ep_interval(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char unit;
unsigned interval = 0;
unsigned in;
in = (desc->bEndpointAddress & USB_DIR_IN);
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_CONTROL:
if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
interval = desc->bInterval;
break;
case USB_ENDPOINT_XFER_ISOC:
interval = 1 << (desc->bInterval - 1);
break;
case USB_ENDPOINT_XFER_BULK:
if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
interval = desc->bInterval;
break;
case USB_ENDPOINT_XFER_INT:
if (udev->speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
else
interval = desc->bInterval;
break;
}
interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
if (interval % 1000)
unit = 'u';
else {
unit = 'm';
interval /= 1000;
}
return sprintf(buf, "%d%cs\n", interval, unit);
}
static EP_ATTR(interval);
static ssize_t show_ep_direction(struct usb_device *udev,
struct usb_endpoint_descriptor *desc, char *buf)
{
char *direction;
if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL)
direction = "both";
else if (desc->bEndpointAddress & USB_DIR_IN)
direction = "in";
else
direction = "out";
return sprintf(buf, "%s\n", direction);
}
static EP_ATTR(direction);
static struct attribute *ep_attrs[] = {
&ep_bLength.attr,
&ep_bEndpointAddress.attr,
&ep_bmAttributes.attr,
&ep_bInterval.attr,
&ep_wMaxPacketSize.attr,
&ep_type.attr,
&ep_interval.attr,
&ep_direction.attr,
NULL,
};
static void ep_object_release(struct kobject *kobj)
{
kfree(to_ep_object(kobj));
}
static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct ep_object *ep_obj = to_ep_object(kobj);
struct ep_attribute *ep_attr = to_ep_attribute(attr);
return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
}
static struct sysfs_ops ep_object_sysfs_ops = {
.show = ep_object_show,
};
static struct kobj_type ep_object_ktype = {
.release = ep_object_release,
.sysfs_ops = &ep_object_sysfs_ops,
.default_attrs = ep_attrs,
};
static void usb_create_ep_files(struct kobject *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
struct ep_object *ep_obj;
struct kobject *kobj;
ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL);
if (!ep_obj)
return;
ep_obj->desc = &endpoint->desc;
ep_obj->udev = udev;
kobj = &ep_obj->kobj;
kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress);
kobj->parent = parent;
kobj->ktype = &ep_object_ktype;
/* Don't use kobject_register, because it generates a hotplug event */
kobject_init(kobj);
if (kobject_add(kobj) == 0)
endpoint->kobj = kobj;
else
kobject_put(kobj);
}
static void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
{
if (endpoint->kobj) {
kobject_del(endpoint->kobj);
kobject_put(endpoint->kobj);
endpoint->kobj = NULL;
}
}
/* Active configuration fields */ /* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string) \ #define usb_actconfig_show(field, multiplier, format_string) \
static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ static ssize_t show_##field (struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
struct usb_host_config *actconfig; \ struct usb_host_config *actconfig; \
@ -46,22 +244,17 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
usb_actconfig_attr (bmAttributes, 1, "%2x\n") usb_actconfig_attr (bmAttributes, 1, "%2x\n")
usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_configuration_string(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct usb_device *udev; struct usb_device *udev;
struct usb_host_config *actconfig; struct usb_host_config *actconfig;
int len;
udev = to_usb_device (dev); udev = to_usb_device (dev);
actconfig = udev->actconfig; actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string)) if ((!actconfig) || (!actconfig->string))
return 0; return 0;
len = sprintf(buf, actconfig->string, PAGE_SIZE); return sprintf(buf, "%s\n", actconfig->string);
if (len < 0)
return 0;
buf[len] = '\n';
buf[len+1] = 0;
return len+1;
} }
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
@ -69,7 +262,8 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
usb_actconfig_show(bConfigurationValue, 1, "%u\n"); usb_actconfig_show(bConfigurationValue, 1, "%u\n");
static ssize_t static ssize_t
set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct usb_device *udev = udev = to_usb_device (dev); struct usb_device *udev = udev = to_usb_device (dev);
int config, value; int config, value;
@ -87,18 +281,13 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
/* String fields */ /* String fields */
#define usb_string_attr(name) \ #define usb_string_attr(name) \
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ static ssize_t show_##name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
int len; \
\ \
udev = to_usb_device (dev); \ udev = to_usb_device (dev); \
len = snprintf(buf, 256, "%s", udev->name); \ return sprintf(buf, "%s\n", udev->name); \
if (len < 0) \
return 0; \
buf[len] = '\n'; \
buf[len+1] = 0; \
return len+1; \
} \ } \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@ -167,7 +356,8 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
/* Descriptor fields */ /* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \ #define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \ static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ show_##field (struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
\ \
@ -183,7 +373,8 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
#define usb_descriptor_attr(field, format_string) \ #define usb_descriptor_attr(field, format_string) \
static ssize_t \ static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ show_##field (struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
\ \
@ -236,19 +427,21 @@ void usb_create_sysfs_dev_files (struct usb_device *udev)
if (udev->serial) if (udev->serial)
device_create_file (dev, &dev_attr_serial); device_create_file (dev, &dev_attr_serial);
device_create_file (dev, &dev_attr_configuration); device_create_file (dev, &dev_attr_configuration);
usb_create_ep_files(&dev->kobj, &udev->ep0, udev);
} }
void usb_remove_sysfs_dev_files (struct usb_device *udev) void usb_remove_sysfs_dev_files (struct usb_device *udev)
{ {
struct device *dev = &udev->dev; struct device *dev = &udev->dev;
usb_remove_ep_files(&udev->ep0);
sysfs_remove_group(&dev->kobj, &dev_attr_grp); sysfs_remove_group(&dev->kobj, &dev_attr_grp);
if (udev->descriptor.iManufacturer) if (udev->manufacturer)
device_remove_file(dev, &dev_attr_manufacturer); device_remove_file(dev, &dev_attr_manufacturer);
if (udev->descriptor.iProduct) if (udev->product)
device_remove_file(dev, &dev_attr_product); device_remove_file(dev, &dev_attr_product);
if (udev->descriptor.iSerialNumber) if (udev->serial)
device_remove_file(dev, &dev_attr_serial); device_remove_file(dev, &dev_attr_serial);
device_remove_file (dev, &dev_attr_configuration); device_remove_file (dev, &dev_attr_configuration);
} }
@ -256,11 +449,13 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
/* Interface fields */ /* Interface fields */
#define usb_intf_attr(field, format_string) \ #define usb_intf_attr(field, format_string) \
static ssize_t \ static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ show_##field (struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \ { \
struct usb_interface *intf = to_usb_interface (dev); \ struct usb_interface *intf = to_usb_interface (dev); \
\ \
return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ return sprintf (buf, format_string, \
intf->cur_altsetting->desc.field); \
} \ } \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@ -271,7 +466,8 @@ usb_intf_attr (bInterfaceClass, "%02x\n")
usb_intf_attr (bInterfaceSubClass, "%02x\n") usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n")
static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_device *udev; struct usb_device *udev;
@ -288,34 +484,28 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute
} }
static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_modalias(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct usb_interface *intf; struct usb_interface *intf;
struct usb_device *udev; struct usb_device *udev;
int len; struct usb_host_interface *alt;
intf = to_usb_interface(dev); intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
alt = intf->cur_altsetting;
len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic", return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
le16_to_cpu(udev->descriptor.idVendor), "ic%02Xisc%02Xip%02X\n",
le16_to_cpu(udev->descriptor.idProduct), le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.bcdDevice), le16_to_cpu(udev->descriptor.idProduct),
udev->descriptor.bDeviceClass, le16_to_cpu(udev->descriptor.bcdDevice),
udev->descriptor.bDeviceSubClass, udev->descriptor.bDeviceClass,
udev->descriptor.bDeviceProtocol); udev->descriptor.bDeviceSubClass,
buf += len; udev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceClass,
if (udev->descriptor.bDeviceClass == 0) { alt->desc.bInterfaceSubClass,
struct usb_host_interface *alt = intf->cur_altsetting; alt->desc.bInterfaceProtocol);
return len + sprintf(buf, "%02Xisc%02Xip%02X\n",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol);
} else {
return len + sprintf(buf, "*isc*ip*\n");
}
} }
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
@ -333,20 +523,47 @@ static struct attribute_group intf_attr_grp = {
.attrs = intf_attrs, .attrs = intf_attrs,
}; };
static inline void usb_create_intf_ep_files(struct usb_interface *intf,
struct usb_device *udev)
{
struct usb_host_interface *iface_desc;
int i;
iface_desc = intf->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i],
udev);
}
static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
{
struct usb_host_interface *iface_desc;
int i;
iface_desc = intf->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
usb_remove_ep_files(&iface_desc->endpoint[i]);
}
void usb_create_sysfs_intf_files (struct usb_interface *intf) void usb_create_sysfs_intf_files (struct usb_interface *intf)
{ {
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
if (intf->cur_altsetting->string) if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
device_create_file(&intf->dev, &dev_attr_interface); device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
} }
void usb_remove_sysfs_intf_files (struct usb_interface *intf) void usb_remove_sysfs_intf_files (struct usb_interface *intf)
{ {
usb_remove_intf_ep_files(intf);
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
if (intf->cur_altsetting->string) if (intf->cur_altsetting->string)
device_remove_file(&intf->dev, &dev_attr_interface); device_remove_file(&intf->dev, &dev_attr_interface);
} }

Просмотреть файл

@ -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)
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)
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,
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,
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,
{ {
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,7 +586,8 @@ 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);
return -ENODEV; return -ENODEV;
@ -615,46 +629,27 @@ 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) { if (add_hotplug_env_var(envp, num_envp, &i,
struct usb_host_interface *alt = intf->cur_altsetting; buffer, buffer_size, &length,
"INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
/* 2.4 only exposed interface zero. in 2.5, hotplug if (add_hotplug_env_var(envp, num_envp, &i,
* agents are called for all interfaces, and can use buffer, buffer_size, &length,
* $DEVPATH/bInterfaceNumber if necessary. "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
*/ le16_to_cpu(usb_dev->descriptor.idVendor),
if (add_hotplug_env_var(envp, num_envp, &i, le16_to_cpu(usb_dev->descriptor.idProduct),
buffer, buffer_size, &length, le16_to_cpu(usb_dev->descriptor.bcdDevice),
"INTERFACE=%d/%d/%d", usb_dev->descriptor.bDeviceClass,
alt->desc.bInterfaceClass, usb_dev->descriptor.bDeviceSubClass,
alt->desc.bInterfaceSubClass, usb_dev->descriptor.bDeviceProtocol,
alt->desc.bInterfaceProtocol)) alt->desc.bInterfaceClass,
return -ENOMEM; alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
if (add_hotplug_env_var(envp, num_envp, &i, return -ENOMEM;
buffer, buffer_size, &length,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
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,
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
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)
{ {
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,
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)
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)
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);
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);
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);
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 {
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)
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 (
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)
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 = {
.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)
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)
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 = {
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
.owner = THIS_MODULE,
// .shutdown = ... // .shutdown = ...
// .suspend = ... // .suspend = ...
// .resume = ... // .resume = ...

Просмотреть файл

@ -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 {
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)
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)
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_)
{ {
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_)
* 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_)
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)
/* 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)
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)
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 = {
.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)
{ {
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)
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);
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)
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);
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,

Просмотреть файл

@ -691,7 +691,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
} }
static void static void
finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status) finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
{ {
u16 count; u16 count;
@ -699,6 +699,8 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
ep->dma_counter = (u16) (req->req.dma + req->req.actual); ep->dma_counter = (u16) (req->req.dma + req->req.actual);
count = dma_dest_len(ep, req->req.dma + req->req.actual); count = dma_dest_len(ep, req->req.dma + req->req.actual);
count += req->req.actual; count += req->req.actual;
if (one)
count--;
if (count <= req->req.length) if (count <= req->req.length)
req->req.actual = count; req->req.actual = count;
@ -747,7 +749,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
if (!list_empty(&ep->queue)) { if (!list_empty(&ep->queue)) {
req = container_of(ep->queue.next, req = container_of(ep->queue.next,
struct omap_req, queue); struct omap_req, queue);
finish_out_dma(ep, req, 0); finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB);
} }
UDC_IRQ_SRC_REG = UDC_RXN_EOT; UDC_IRQ_SRC_REG = UDC_RXN_EOT;
@ -925,7 +927,7 @@ static void dma_channel_release(struct omap_ep *ep)
while (UDC_RXDMA_CFG_REG & mask) while (UDC_RXDMA_CFG_REG & mask)
udelay(10); udelay(10);
if (req) if (req)
finish_out_dma(ep, req, -ECONNRESET); finish_out_dma(ep, req, -ECONNRESET, 0);
} }
omap_free_dma(ep->lch); omap_free_dma(ep->lch);
ep->dma_channel = 0; ep->dma_channel = 0;
@ -1786,8 +1788,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
udc->driver->suspend(&udc->gadget); udc->driver->suspend(&udc->gadget);
spin_lock(&udc->lock); spin_lock(&udc->lock);
} }
if (udc->transceiver)
otg_set_suspend(udc->transceiver, 1);
} else { } else {
VDBG("resume\n"); VDBG("resume\n");
if (udc->transceiver)
otg_set_suspend(udc->transceiver, 0);
if (udc->gadget.speed == USB_SPEED_FULL if (udc->gadget.speed == USB_SPEED_FULL
&& udc->driver->resume) { && udc->driver->resume) {
spin_unlock(&udc->lock); spin_unlock(&udc->lock);
@ -2943,6 +2949,7 @@ static int omap_udc_resume(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 = omap_udc_probe, .probe = omap_udc_probe,
.remove = __exit_p(omap_udc_remove), .remove = __exit_p(omap_udc_remove),

Просмотреть файл

@ -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 = {
.driver = { .driver = {
.name = (char *) shortname, .name = (char *) shortname,
.owner = THIS_MODULE,
// .shutdown = ... // .shutdown = ...
// .suspend = ... // .suspend = ...
// .resume = ... // .resume = ...

Просмотреть файл

@ -1,8 +1,9 @@
# #
# 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

Просмотреть файл

@ -182,6 +182,9 @@ static int ehci_halt (struct ehci_hcd *ehci)
{ {
u32 temp = readl (&ehci->regs->status); u32 temp = readl (&ehci->regs->status);
/* disable any irqs left enabled by previous code */
writel (0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0) if ((temp & STS_HALT) != 0)
return 0; return 0;
@ -297,50 +300,17 @@ static void ehci_watchdog (unsigned long param)
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
} }
#ifdef CONFIG_PCI /* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
* This forcibly disables dma and IRQs, helping kexec and other cases
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... * where the next system software may expect clean state.
* off the controller (maybe it can boot from highspeed USB disks).
*/ */
static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
{
struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
/* always say Linux will own the hardware */
pci_write_config_byte(pdev, where + 3, 1);
/* maybe wait a while for BIOS to respond */
if (cap & (1 << 16)) {
int msec = 5000;
do {
msleep(10);
msec -= 10;
pci_read_config_dword(pdev, where, &cap);
} while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) {
ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
where, cap);
// some BIOS versions seem buggy...
// return 1;
ehci_warn (ehci, "continuing after BIOS bug...\n");
/* disable all SMIs, and clear "BIOS owns" flag */
pci_write_config_dword(pdev, where + 4, 0);
pci_write_config_byte(pdev, where + 2, 0);
} else
ehci_dbg(ehci, "BIOS handoff succeeded\n");
}
return 0;
}
#endif
static int static int
ehci_reboot (struct notifier_block *self, unsigned long code, void *null) ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
{ {
struct ehci_hcd *ehci; struct ehci_hcd *ehci;
ehci = container_of (self, struct ehci_hcd, reboot_notifier); ehci = container_of (self, struct ehci_hcd, reboot_notifier);
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */ /* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag); writel (0, &ehci->regs->configured_flag);
@ -363,156 +333,90 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
msleep(20); msleep(20);
} }
/*-------------------------------------------------------------------------*/
/* called by khubd or root hub init threads */ /*
* ehci_work is called from some interrupts, timers, and so on.
static int ehci_hc_reset (struct usb_hcd *hcd) * it calls driver completion functions, after dropping ehci->lock.
*/
static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); timer_action_done (ehci, TIMER_IO_WATCHDOG);
u32 temp; if (ehci->reclaim_ready)
unsigned count = 256/4; end_unlink_async (ehci, regs);
spin_lock_init (&ehci->lock); /* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
* attempts at re-entrant schedule scanning.
*/
if (ehci->scanning)
return;
ehci->scanning = 1;
scan_async (ehci, regs);
if (ehci->next_uframe != -1)
scan_periodic (ehci, regs);
ehci->scanning = 0;
ehci->caps = hcd->regs; /* the IO watchdog guards against hardware or driver bugs that
ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); * misplace IRQs, and should let us run completely without IRQs.
dbg_hcs_params (ehci, "reset"); * such lossage has been observed on both VT6202 and VT8235.
dbg_hcc_params (ehci, "reset"); */
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
/* cache this readonly data; minimize chip reads */ (ehci->async->qh_next.ptr != NULL ||
ehci->hcs_params = readl (&ehci->caps->hcs_params); ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG);
#ifdef CONFIG_PCI
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
switch (pdev->vendor) {
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
ehci->is_tdi_rh_tt = 1;
tdi_reset (ehci);
}
break;
case PCI_VENDOR_ID_AMD:
/* AMD8111 EHCI doesn't work, according to AMD errata */
if (pdev->device == 0x7463) {
ehci_info (ehci, "ignoring AMD8111 (errata)\n");
return -EIO;
}
break;
case PCI_VENDOR_ID_NVIDIA:
/* NVidia reports that certain chips don't handle
* QH, ITD, or SITD addresses above 2GB. (But TD,
* data buffer, and periodic schedule are normal.)
*/
switch (pdev->device) {
case 0x003c: /* MCP04 */
case 0x005b: /* CK804 */
case 0x00d8: /* CK8 */
case 0x00e8: /* CK8S */
if (pci_set_consistent_dma_mask(pdev,
DMA_31BIT_MASK) < 0)
ehci_warn (ehci, "can't enable NVidia "
"workaround for >2GB RAM\n");
break;
}
break;
}
/* optional debug port, normally in the first BAR */
temp = pci_find_capability (pdev, 0x0a);
if (temp) {
pci_read_config_dword(pdev, temp, &temp);
temp >>= 16;
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = hcd->regs + temp;
temp = readl (&ehci->debug->control);
ehci_info (ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
? " IN USE"
: "");
if (!(temp & DBGP_ENABLED))
ehci->debug = NULL;
}
}
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
} else
temp = 0;
/* EHCI 0.96 and later may have "extended capabilities" */
while (temp && count--) {
u32 cap;
pci_read_config_dword (to_pci_dev(hcd->self.controller),
temp, &cap);
ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff */
if (bios_handoff (ehci, temp, cap) != 0)
return -EOPNOTSUPP;
break;
case 0: /* illegal reserved capability */
ehci_warn (ehci, "illegal capability!\n");
cap = 0;
/* FALLTHROUGH */
default: /* unknown */
break;
}
temp = (cap >> 8) & 0xff;
}
if (!count) {
ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
return -EIO;
}
if (ehci_is_TDI(ehci))
ehci_reset (ehci);
#endif
ehci_port_power (ehci, 0);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
temp &= 0x0f;
if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
ehci_dbg (ehci, "bogus port configuration: "
"cc=%d x pcc=%d < ports=%d\n",
HCS_N_CC(ehci->hcs_params),
HCS_N_PCC(ehci->hcs_params),
HCS_N_PORTS(ehci->hcs_params));
#ifdef CONFIG_PCI
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
pdev = to_pci_dev(hcd->self.controller);
switch (pdev->vendor) {
case 0x17a0: /* GENESYS */
/* GL880S: should be PORTS=2 */
temp |= (ehci->hcs_params & ~0xf);
ehci->hcs_params = temp;
break;
case PCI_VENDOR_ID_NVIDIA:
/* NF4: should be PCC=10 */
break;
}
}
#endif
}
/* force HC to halt state */
return ehci_halt (ehci);
} }
static int ehci_start (struct usb_hcd *hcd) static void ehci_stop (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
ehci_dbg (ehci, "stop\n");
/* Turn off port power on all root hub ports. */
ehci_port_power (ehci, 0);
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
ehci_quiesce (ehci);
ehci_reset (ehci);
writel (0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
spin_lock_irq (&ehci->lock);
if (ehci->async)
ehci_work (ehci, NULL);
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
ehci->stats.lost_iaa);
ehci_dbg (ehci, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
}
static int ehci_run (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp; u32 temp;
int retval; int retval;
u32 hcc_params; u32 hcc_params;
u8 sbrn = 0;
int first; int first;
/* skip some things on restart paths */ /* skip some things on restart paths */
@ -551,27 +455,6 @@ static int ehci_start (struct usb_hcd *hcd)
} }
writel (ehci->periodic_dma, &ehci->regs->frame_list); writel (ehci->periodic_dma, &ehci->regs->frame_list);
#ifdef CONFIG_PCI
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
u16 port_wake;
pdev = to_pci_dev(hcd->self.controller);
/* Serial Bus Release Number is at PCI 0x60 offset */
pci_read_config_byte(pdev, 0x60, &sbrn);
/* port wake capability, reported by boot firmware */
pci_read_config_word(pdev, 0x62, &port_wake);
hcd->can_wakeup = (port_wake & 1) != 0;
/* help hc dma work well with cachelines */
retval = pci_set_mwi(pdev);
if (retval)
ehci_dbg(ehci, "unable to enable MWI - not fatal.\n");
}
#endif
/* /*
* dedicate a qh for the async ring head, since we couldn't unlink * dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it * a 'real' qh without stopping the async schedule [4.8]. use it
@ -667,7 +550,7 @@ static int ehci_start (struct usb_hcd *hcd)
temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci, ehci_info (ehci,
"USB %x.%x %s, EHCI %x.%02x, driver %s\n", "USB %x.%x %s, EHCI %x.%02x, driver %s\n",
((sbrn & 0xf0)>>4), (sbrn & 0x0f), ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
first ? "initialized" : "restarted", first ? "initialized" : "restarted",
temp >> 8, temp & 0xff, DRIVER_VERSION); temp >> 8, temp & 0xff, DRIVER_VERSION);
@ -679,188 +562,6 @@ static int ehci_start (struct usb_hcd *hcd)
return 0; return 0;
} }
/* always called by thread; normally rmmod */
static void ehci_stop (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
ehci_dbg (ehci, "stop\n");
/* Turn off port power on all root hub ports. */
ehci_port_power (ehci, 0);
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
ehci_quiesce (ehci);
ehci_reset (ehci);
writel (0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
spin_lock_irq (&ehci->lock);
if (ehci->async)
ehci_work (ehci, NULL);
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS
ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
ehci->stats.lost_iaa);
ehci_dbg (ehci, "complete %ld unlink %ld\n",
ehci->stats.complete, ehci->stats.unlink);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
}
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
/* suspend/resume, section 4.3 */
/* These routines rely on the bus (pci, platform, etc)
* to handle powerdown and wakeup, and currently also on
* transceivers that don't need any software attention to set up
* the right sort of wakeup.
*/
static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
if (time_before (jiffies, ehci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub, message);
#else
usb_lock_device (hcd->self.root_hub);
(void) ehci_hub_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
// save (PCI) FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew
return 0;
}
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
unsigned port;
struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL;
// maybe restore (PCI) FLADJ
if (time_before (jiffies, ehci->next_statechange))
msleep (100);
/* If any port is suspended (or owned by the companion),
* we know we can/must resume the HC (and mustn't reset it).
*/
for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
u32 status;
port--;
status = readl (&ehci->regs->port_status [port]);
if (!(status & PORT_POWER))
continue;
if (status & (PORT_SUSPEND | PORT_OWNER)) {
down (&hcd->self.root_hub->serialize);
retval = ehci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize);
break;
}
if (!root->children [port])
continue;
dbg_port (ehci, __FUNCTION__, port + 1, status);
usb_set_device_state (root->children[port],
USB_STATE_NOTATTACHED);
}
/* Else reset, to cope with power loss or flush-to-storage
* style "resume" having activated BIOS during reboot.
*/
if (port == 0) {
(void) ehci_halt (ehci);
(void) ehci_reset (ehci);
(void) ehci_hc_reset (hcd);
/* emptying the schedule aborts any urbs */
spin_lock_irq (&ehci->lock);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work (ehci, NULL);
spin_unlock_irq (&ehci->lock);
/* restart; khubd will disconnect devices */
retval = ehci_start (hcd);
/* here we "know" root ports should always stay powered;
* but some controllers may lose all power.
*/
ehci_port_power (ehci, 1);
}
return retval;
}
#endif
/*-------------------------------------------------------------------------*/
/*
* ehci_work is called from some interrupts, timers, and so on.
* it calls driver completion functions, after dropping ehci->lock.
*/
static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
if (ehci->reclaim_ready)
end_unlink_async (ehci, regs);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
* attempts at re-entrant schedule scanning.
*/
if (ehci->scanning)
return;
ehci->scanning = 1;
scan_async (ehci, regs);
if (ehci->next_uframe != -1)
scan_periodic (ehci, regs);
ehci->scanning = 0;
/* the IO watchdog guards against hardware or driver bugs that
* misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235.
*/
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
(ehci->async->qh_next.ptr != NULL ||
ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG);
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
@ -1171,106 +872,24 @@ done:
return; return;
} }
/*-------------------------------------------------------------------------*/ static int ehci_get_frame (struct usb_hcd *hcd)
{
static const struct hc_driver ehci_driver = { struct ehci_hcd *ehci = hcd_to_ehci (hcd);
.description = hcd_name, return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
.product_desc = "EHCI Host Controller", }
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_hc_reset,
.start = ehci_start,
#ifdef CONFIG_PM
.suspend = ehci_suspend,
.resume = ehci_resume,
#endif
.stop = ehci_stop,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.hub_suspend = ehci_hub_suspend,
.hub_resume = ehci_hub_resume,
};
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* EHCI 1.0 doesn't require PCI */
#ifdef CONFIG_PCI
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
.driver_data = (unsigned long) &ehci_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE (pci, pci_ids);
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver ehci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
};
#endif /* PCI */
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_DESCRIPTION (DRIVER_INFO); MODULE_DESCRIPTION (DRIVER_INFO);
MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
static int __init init (void) #ifdef CONFIG_PCI
{ #include "ehci-pci.c"
if (usb_disabled()) #endif
return -ENODEV;
pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", #if !defined(CONFIG_PCI)
hcd_name, #error "missing bus glue for ehci-hcd"
sizeof (struct ehci_qh), sizeof (struct ehci_qtd), #endif
sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
return pci_register_driver (&ehci_pci_driver);
}
module_init (init);
static void __exit cleanup (void)
{
pci_unregister_driver (&ehci_pci_driver);
}
module_exit (cleanup);

Просмотреть файл

@ -30,7 +30,7 @@
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ehci_hub_suspend (struct usb_hcd *hcd) static int ehci_bus_suspend (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int port; int port;
@ -83,7 +83,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
/* caller has locked the root hub, and should reset/reinit on error */ /* caller has locked the root hub, and should reset/reinit on error */
static int ehci_hub_resume (struct usb_hcd *hcd) static int ehci_bus_resume (struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp; u32 temp;
@ -159,8 +159,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
#else #else
#define ehci_hub_suspend NULL #define ehci_bus_suspend NULL
#define ehci_hub_resume NULL #define ehci_bus_resume NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */

415
drivers/usb/host/ehci-pci.c Normal file
Просмотреть файл

@ -0,0 +1,415 @@
/*
* EHCI HCD (Host Controller Driver) PCI Bus Glue.
*
* Copyright (c) 2000-2004 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef CONFIG_PCI
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
/*-------------------------------------------------------------------------*/
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
* off the controller (maybe it can boot from highspeed USB disks).
*/
static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
{
struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
/* always say Linux will own the hardware */
pci_write_config_byte(pdev, where + 3, 1);
/* maybe wait a while for BIOS to respond */
if (cap & (1 << 16)) {
int msec = 5000;
do {
msleep(10);
msec -= 10;
pci_read_config_dword(pdev, where, &cap);
} while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) {
ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
where, cap);
// some BIOS versions seem buggy...
// return 1;
ehci_warn (ehci, "continuing after BIOS bug...\n");
/* disable all SMIs, and clear "BIOS owns" flag */
pci_write_config_dword(pdev, where + 4, 0);
pci_write_config_byte(pdev, where + 2, 0);
} else
ehci_dbg(ehci, "BIOS handoff succeeded\n");
}
return 0;
}
/* called by khubd or root hub init threads */
static int ehci_pci_reset (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
unsigned count = 256/4;
spin_lock_init (&ehci->lock);
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase));
dbg_hcs_params (ehci, "reset");
dbg_hcc_params (ehci, "reset");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
switch (pdev->vendor) {
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
ehci->is_tdi_rh_tt = 1;
tdi_reset (ehci);
}
break;
case PCI_VENDOR_ID_AMD:
/* AMD8111 EHCI doesn't work, according to AMD errata */
if (pdev->device == 0x7463) {
ehci_info (ehci, "ignoring AMD8111 (errata)\n");
return -EIO;
}
break;
case PCI_VENDOR_ID_NVIDIA:
/* NVidia reports that certain chips don't handle
* QH, ITD, or SITD addresses above 2GB. (But TD,
* data buffer, and periodic schedule are normal.)
*/
switch (pdev->device) {
case 0x003c: /* MCP04 */
case 0x005b: /* CK804 */
case 0x00d8: /* CK8 */
case 0x00e8: /* CK8S */
if (pci_set_consistent_dma_mask(pdev,
DMA_31BIT_MASK) < 0)
ehci_warn (ehci, "can't enable NVidia "
"workaround for >2GB RAM\n");
break;
}
break;
}
/* optional debug port, normally in the first BAR */
temp = pci_find_capability (pdev, 0x0a);
if (temp) {
pci_read_config_dword(pdev, temp, &temp);
temp >>= 16;
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = hcd->regs + temp;
temp = readl (&ehci->debug->control);
ehci_info (ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
? " IN USE"
: "");
if (!(temp & DBGP_ENABLED))
ehci->debug = NULL;
}
}
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
} else
temp = 0;
/* EHCI 0.96 and later may have "extended capabilities" */
while (temp && count--) {
u32 cap;
pci_read_config_dword (to_pci_dev(hcd->self.controller),
temp, &cap);
ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
switch (cap & 0xff) {
case 1: /* BIOS/SMM/... handoff */
if (bios_handoff (ehci, temp, cap) != 0)
return -EOPNOTSUPP;
break;
case 0: /* illegal reserved capability */
ehci_warn (ehci, "illegal capability!\n");
cap = 0;
/* FALLTHROUGH */
default: /* unknown */
break;
}
temp = (cap >> 8) & 0xff;
}
if (!count) {
ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
return -EIO;
}
if (ehci_is_TDI(ehci))
ehci_reset (ehci);
ehci_port_power (ehci, 0);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
temp &= 0x0f;
if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
ehci_dbg (ehci, "bogus port configuration: "
"cc=%d x pcc=%d < ports=%d\n",
HCS_N_CC(ehci->hcs_params),
HCS_N_PCC(ehci->hcs_params),
HCS_N_PORTS(ehci->hcs_params));
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
pdev = to_pci_dev(hcd->self.controller);
switch (pdev->vendor) {
case 0x17a0: /* GENESYS */
/* GL880S: should be PORTS=2 */
temp |= (ehci->hcs_params & ~0xf);
ehci->hcs_params = temp;
break;
case PCI_VENDOR_ID_NVIDIA:
/* NF4: should be PCC=10 */
break;
}
}
}
/* force HC to halt state */
return ehci_halt (ehci);
}
static int ehci_pci_start (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int result = 0;
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
u16 port_wake;
pdev = to_pci_dev(hcd->self.controller);
/* Serial Bus Release Number is at PCI 0x60 offset */
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
/* port wake capability, reported by boot firmware */
pci_read_config_word(pdev, 0x62, &port_wake);
hcd->can_wakeup = (port_wake & 1) != 0;
/* help hc dma work well with cachelines */
result = pci_set_mwi(pdev);
if (result)
ehci_dbg(ehci, "unable to enable MWI - not fatal.\n");
}
return ehci_run (hcd);
}
/* always called by thread; normally rmmod */
static void ehci_pci_stop (struct usb_hcd *hcd)
{
ehci_stop (hcd);
}
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
/* suspend/resume, section 4.3 */
/* These routines rely on the bus (pci, platform, etc)
* to handle powerdown and wakeup, and currently also on
* transceivers that don't need any software attention to set up
* the right sort of wakeup.
*/
static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
if (time_before (jiffies, ehci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub);
#else
usb_lock_device (hcd->self.root_hub);
(void) ehci_bus_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
// save (PCI) FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew
return 0;
}
static int ehci_pci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
unsigned port;
struct usb_device *root = hcd->self.root_hub;
int retval = -EINVAL;
// maybe restore (PCI) FLADJ
if (time_before (jiffies, ehci->next_statechange))
msleep (100);
/* If any port is suspended (or owned by the companion),
* we know we can/must resume the HC (and mustn't reset it).
*/
for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
u32 status;
port--;
status = readl (&ehci->regs->port_status [port]);
if (!(status & PORT_POWER))
continue;
if (status & (PORT_SUSPEND | PORT_OWNER)) {
down (&hcd->self.root_hub->serialize);
retval = ehci_bus_resume (hcd);
up (&hcd->self.root_hub->serialize);
break;
}
if (!root->children [port])
continue;
dbg_port (ehci, __FUNCTION__, port + 1, status);
usb_set_device_state (root->children[port],
USB_STATE_NOTATTACHED);
}
/* Else reset, to cope with power loss or flush-to-storage
* style "resume" having activated BIOS during reboot.
*/
if (port == 0) {
(void) ehci_halt (ehci);
(void) ehci_reset (ehci);
(void) ehci_pci_reset (hcd);
/* emptying the schedule aborts any urbs */
spin_lock_irq (&ehci->lock);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work (ehci, NULL);
spin_unlock_irq (&ehci->lock);
/* restart; khubd will disconnect devices */
retval = ehci_run (hcd);
/* here we "know" root ports should always stay powered;
* but some controllers may lose all power.
*/
ehci_port_power (ehci, 1);
}
return retval;
}
#endif
static const struct hc_driver ehci_pci_hc_driver = {
.description = hcd_name,
.product_desc = "EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_pci_reset,
.start = ehci_pci_start,
#ifdef CONFIG_PM
.suspend = ehci_pci_suspend,
.resume = ehci_pci_resume,
#endif
.stop = ehci_pci_stop,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
};
/*-------------------------------------------------------------------------*/
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
.driver_data = (unsigned long) &ehci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE (pci, pci_ids);
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver ehci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.owner = THIS_MODULE,
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
};
static int __init ehci_hcd_pci_init (void)
{
if (usb_disabled())
return -ENODEV;
pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
hcd_name,
sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
return pci_register_driver (&ehci_pci_driver);
}
module_init (ehci_hcd_pci_init);
static void __exit ehci_hcd_pci_cleanup (void)
{
pci_unregister_driver (&ehci_pci_driver);
}
module_exit (ehci_hcd_pci_cleanup);

Просмотреть файл

@ -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 */

Просмотреть файл

@ -638,7 +638,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+ msecs_to_jiffies(20) + 1); + msecs_to_jiffies(20) + 1);
if (intstat & HCINT_RD) { if (intstat & HCINT_RD) {
DBG("---- remote wakeup\n"); DBG("---- remote wakeup\n");
schedule_work(&isp116x->rh_resume); usb_hcd_resume_root_hub(hcd);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
irqstat &= ~HCuPINT_OPR; irqstat &= ~HCuPINT_OPR;
@ -1160,7 +1160,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd,
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int isp116x_hub_suspend(struct usb_hcd *hcd) static int isp116x_bus_suspend(struct usb_hcd *hcd)
{ {
struct isp116x *isp116x = hcd_to_isp116x(hcd); struct isp116x *isp116x = hcd_to_isp116x(hcd);
unsigned long flags; unsigned long flags;
@ -1200,7 +1200,7 @@ static int isp116x_hub_suspend(struct usb_hcd *hcd)
return ret; return ret;
} }
static int isp116x_hub_resume(struct usb_hcd *hcd) static int isp116x_bus_resume(struct usb_hcd *hcd)
{ {
struct isp116x *isp116x = hcd_to_isp116x(hcd); struct isp116x *isp116x = hcd_to_isp116x(hcd);
u32 val; u32 val;
@ -1263,21 +1263,11 @@ static int isp116x_hub_resume(struct usb_hcd *hcd)
return 0; return 0;
} }
static void isp116x_rh_resume(void *_hcd)
{
struct usb_hcd *hcd = _hcd;
usb_resume_device(hcd->self.root_hub);
}
#else #else
#define isp116x_hub_suspend NULL #define isp116x_bus_suspend NULL
#define isp116x_hub_resume NULL #define isp116x_bus_resume NULL
static void isp116x_rh_resume(void *_hcd)
{
}
#endif #endif
@ -1636,8 +1626,8 @@ static struct hc_driver isp116x_hc_driver = {
.hub_status_data = isp116x_hub_status_data, .hub_status_data = isp116x_hub_status_data,
.hub_control = isp116x_hub_control, .hub_control = isp116x_hub_control,
.hub_suspend = isp116x_hub_suspend, .bus_suspend = isp116x_bus_suspend,
.hub_resume = isp116x_hub_resume, .bus_resume = isp116x_bus_resume,
}; };
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
@ -1732,7 +1722,6 @@ static int __init isp116x_probe(struct device *dev)
isp116x->addr_reg = addr_reg; isp116x->addr_reg = addr_reg;
spin_lock_init(&isp116x->lock); spin_lock_init(&isp116x->lock);
INIT_LIST_HEAD(&isp116x->async); INIT_LIST_HEAD(&isp116x->async);
INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
isp116x->board = dev->platform_data; isp116x->board = dev->platform_data;
if (!isp116x->board) { if (!isp116x->board) {
@ -1777,16 +1766,10 @@ static int __init isp116x_probe(struct device *dev)
static int isp116x_suspend(struct device *dev, pm_message_t state) static int isp116x_suspend(struct device *dev, pm_message_t state)
{ {
int ret = 0; int ret = 0;
struct usb_hcd *hcd = dev_get_drvdata(dev);
VDBG("%s: state %x\n", __func__, state); VDBG("%s: state %x\n", __func__, state);
ret = usb_suspend_device(hcd->self.root_hub, state); dev->power.power_state = state;
if (!ret) {
dev->power.power_state = state;
INFO("%s suspended\n", hcd_name);
} else
ERR("%s suspend failed\n", hcd_name);
return ret; return ret;
} }
@ -1797,15 +1780,11 @@ static int isp116x_suspend(struct device *dev, pm_message_t state)
static int isp116x_resume(struct device *dev) static int isp116x_resume(struct device *dev)
{ {
int ret = 0; int ret = 0;
struct usb_hcd *hcd = dev_get_drvdata(dev);
VDBG("%s: state %x\n", __func__, dev->power.power_state); VDBG("%s: state %x\n", __func__, dev->power.power_state);
ret = usb_resume_device(hcd->self.root_hub); dev->power.power_state = PMSG_ON;
if (!ret) {
dev->power.power_state = PMSG_ON;
VDBG("%s resumed\n", (char *)hcd_name);
}
return ret; return ret;
} }

Просмотреть файл

@ -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;

Просмотреть файл

@ -214,6 +214,11 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -259,6 +264,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
static struct device_driver ohci_hcd_au1xxx_driver = { static struct device_driver ohci_hcd_au1xxx_driver = {
.name = "au1xxx-ohci", .name = "au1xxx-ohci",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = ohci_hcd_au1xxx_drv_probe, .probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove, .remove = ohci_hcd_au1xxx_drv_remove,

Просмотреть файл

@ -193,10 +193,6 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
maybe_print_eds (controller, "donehead", maybe_print_eds (controller, "donehead",
ohci_readl (controller, &regs->donehead), next, size); ohci_readl (controller, &regs->donehead), next, size);
/* broken fminterval means traffic won't flow! */
ohci_dbg (controller, "fminterval %08x\n",
ohci_readl (controller, &regs->fminterval));
} }
#define dbg_port_sw(hc,num,value,next,size) \ #define dbg_port_sw(hc,num,value,next,size) \

Просмотреть файл

@ -723,7 +723,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
ohci_vdbg (ohci, "resume detect\n"); ohci_vdbg (ohci, "resume detect\n");
ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus); ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
if (hcd->state != HC_STATE_QUIESCING) if (hcd->state != HC_STATE_QUIESCING)
schedule_work(&ohci->rh_resume); usb_hcd_resume_root_hub(hcd);
} }
if (ints & OHCI_INTR_WDH) { if (ints & OHCI_INTR_WDH) {
@ -791,7 +791,7 @@ static void ohci_stop (struct usb_hcd *hcd)
/* must not be called from interrupt context */ /* must not be called from interrupt context */
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) #ifdef CONFIG_PM
static int ohci_restart (struct ohci_hcd *ohci) static int ohci_restart (struct ohci_hcd *ohci)
{ {

Просмотреть файл

@ -36,7 +36,7 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) #ifdef CONFIG_PM
#define OHCI_SCHED_ENABLES \ #define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@ -45,7 +45,7 @@ static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
static int ohci_restart (struct ohci_hcd *ohci); static int ohci_restart (struct ohci_hcd *ohci);
static int ohci_hub_suspend (struct usb_hcd *hcd) static int ohci_bus_suspend (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int status = 0; int status = 0;
@ -73,7 +73,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
ohci_dbg (ohci, "suspend root hub\n"); ohci_dbg (ohci, "suspend root hub\n");
/* First stop any processing */ /* First stop any processing */
hcd->state = HC_STATE_QUIESCING;
if (ohci->hc_control & OHCI_SCHED_ENABLES) { if (ohci->hc_control & OHCI_SCHED_ENABLES) {
int limit; int limit;
@ -108,7 +107,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
else else
ohci->hc_control &= ~OHCI_CTRL_RWE; ohci->hc_control &= ~OHCI_CTRL_RWE;
/* Suspend hub */ /* Suspend hub ... this is the "global (to this bus) suspend" mode,
* which doesn't imply ports will first be individually suspended.
*/
ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control &= ~OHCI_CTRL_HCFS;
ohci->hc_control |= OHCI_USB_SUSPEND; ohci->hc_control |= OHCI_USB_SUSPEND;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
@ -118,8 +119,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
ohci->next_statechange = jiffies + msecs_to_jiffies (5); ohci->next_statechange = jiffies + msecs_to_jiffies (5);
done: done:
/* external suspend vs self autosuspend ... same effect */
if (status == 0) if (status == 0)
hcd->state = HC_STATE_SUSPENDED; usb_hcd_suspend_root_hub(hcd);
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
return status; return status;
} }
@ -133,7 +135,7 @@ static inline struct ed *find_head (struct ed *ed)
} }
/* caller has locked the root hub */ /* caller has locked the root hub */
static int ohci_hub_resume (struct usb_hcd *hcd) static int ohci_bus_resume (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
u32 temp, enables; u32 temp, enables;
@ -146,7 +148,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
/* this can happen after suspend-to-disk */ /* this can happen after resuming a swsusp snapshot */
if (hcd->state == HC_STATE_RESUMING) { if (hcd->state == HC_STATE_RESUMING) {
ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
ohci->hc_control); ohci->hc_control);
@ -169,11 +171,12 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
ohci_info (ohci, "wakeup\n"); ohci_info (ohci, "wakeup\n");
break; break;
case OHCI_USB_OPER: case OHCI_USB_OPER:
ohci_dbg (ohci, "already resumed\n"); /* this can happen after resuming a swsusp snapshot */
status = 0; ohci_dbg (ohci, "snapshot resume? reinit\n");
status = -EBUSY;
break; break;
default: /* RESET, we lost power */ default: /* RESET, we lost power */
ohci_dbg (ohci, "root hub hardware reset\n"); ohci_dbg (ohci, "lost power\n");
status = -EBUSY; status = -EBUSY;
} }
spin_unlock_irq (&ohci->lock); spin_unlock_irq (&ohci->lock);
@ -198,8 +201,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
} }
/* Some controllers (lucent erratum) need extra-long delays */ /* Some controllers (lucent erratum) need extra-long delays */
hcd->state = HC_STATE_RESUMING; msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);
mdelay (20 /* usb 11.5.1.10 */ + 15);
temp = ohci_readl (ohci, &ohci->regs->control); temp = ohci_readl (ohci, &ohci->regs->control);
temp &= OHCI_CTRL_HCFS; temp &= OHCI_CTRL_HCFS;
@ -273,28 +275,10 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control);
} }
hcd->state = HC_STATE_RUNNING;
return 0; return 0;
} }
static void ohci_rh_resume (void *_hcd) #endif /* CONFIG_PM */
{
struct usb_hcd *hcd = _hcd;
usb_lock_device (hcd->self.root_hub);
(void) ohci_hub_resume (hcd);
usb_unlock_device (hcd->self.root_hub);
}
#else
static void ohci_rh_resume (void *_hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (_hcd);
ohci_dbg(ohci, "rh_resume ??\n");
}
#endif /* CONFIG_USB_SUSPEND || CONFIG_PM */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -367,7 +351,6 @@ done:
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* save power by suspending idle root hubs; /* save power by suspending idle root hubs;
* INTR_RD wakes us when there's work * INTR_RD wakes us when there's work
* NOTE: if we can do this, we don't need a root hub timer!
*/ */
if (can_suspend if (can_suspend
&& !changed && !changed
@ -379,8 +362,7 @@ done:
&& usb_trylock_device (hcd->self.root_hub) && usb_trylock_device (hcd->self.root_hub)
) { ) {
ohci_vdbg (ohci, "autosuspend\n"); ohci_vdbg (ohci, "autosuspend\n");
(void) ohci_hub_suspend (hcd); (void) ohci_bus_suspend (hcd);
hcd->state = HC_STATE_RUNNING;
usb_unlock_device (hcd->self.root_hub); usb_unlock_device (hcd->self.root_hub);
} }
#endif #endif
@ -554,7 +536,7 @@ static int ohci_hub_control (
temp = RH_PS_POCI; temp = RH_PS_POCI;
if ((ohci->hc_control & OHCI_CTRL_HCFS) if ((ohci->hc_control & OHCI_CTRL_HCFS)
!= OHCI_USB_OPER) != OHCI_USB_OPER)
schedule_work (&ohci->rh_resume); usb_hcd_resume_root_hub(hcd);
break; break;
case USB_PORT_FEAT_C_SUSPEND: case USB_PORT_FEAT_C_SUSPEND:
temp = RH_PS_PSSC; temp = RH_PS_PSSC;

Просмотреть файл

@ -193,6 +193,11 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -239,6 +244,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct device *dev)
static struct device_driver ohci_hcd_lh7a404_driver = { static struct device_driver ohci_hcd_lh7a404_driver = {
.name = "lh7a404-ohci", .name = "lh7a404-ohci",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = ohci_hcd_lh7a404_drv_probe, .probe = ohci_hcd_lh7a404_drv_probe,
.remove = ohci_hcd_lh7a404_drv_remove, .remove = ohci_hcd_lh7a404_drv_remove,

Просмотреть файл

@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies; ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock); spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending); INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
ohci->reboot_notifier.notifier_call = ohci_reboot; ohci->reboot_notifier.notifier_call = ohci_reboot;
} }

Просмотреть файл

@ -420,9 +420,9 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
.hub_suspend = ohci_hub_suspend, .bus_suspend = ohci_bus_suspend,
.hub_resume = ohci_hub_resume, .bus_resume = ohci_bus_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset, .start_port_reset = ohci_start_port_reset,
}; };
@ -458,41 +458,29 @@ static int ohci_hcd_omap_drv_remove(struct device *dev)
static int ohci_omap_suspend(struct device *dev, pm_message_t message) static int ohci_omap_suspend(struct device *dev, pm_message_t message)
{ {
struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev));
int status = -EINVAL;
down(&ohci_to_hcd(ohci)->self.root_hub->serialize); if (time_before(jiffies, ohci->next_statechange))
status = ohci_hub_suspend(ohci_to_hcd(ohci)); msleep(5);
if (status == 0) { ohci->next_statechange = jiffies;
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->self.root_hub->state = omap_ohci_clock_power(0);
USB_STATE_SUSPENDED; ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; dev->power.power_state = PMSG_SUSPEND;
dev->power.power_state = PMSG_SUSPEND; return 0;
}
up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
return status;
} }
static int ohci_omap_resume(struct device *dev) static int ohci_omap_resume(struct device *dev)
{ {
struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev));
int status = 0;
if (time_before(jiffies, ohci->next_statechange)) if (time_before(jiffies, ohci->next_statechange))
msleep(5); msleep(5);
ohci->next_statechange = jiffies; ohci->next_statechange = jiffies;
omap_ohci_clock_power(1); omap_ohci_clock_power(1);
#ifdef CONFIG_USB_SUSPEND dev->power.power_state = PMSG_ON;
/* get extra cleanup even if remote wakeup isn't in use */ usb_hcd_resume_root_hub(dev_get_drvdata(dev));
status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); return 0;
#else
down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
status = ohci_hub_resume(ohci_to_hcd(ohci));
up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
#endif
if (status == 0)
dev->power.power_state = PMSG_ON;
return status;
} }
#endif #endif
@ -504,6 +492,7 @@ static int ohci_omap_resume(struct device *dev)
*/ */
static struct device_driver ohci_hcd_omap_driver = { static struct device_driver ohci_hcd_omap_driver = {
.name = "ohci", .name = "ohci",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = ohci_hcd_omap_drv_probe, .probe = ohci_hcd_omap_drv_probe,
.remove = ohci_hcd_omap_drv_remove, .remove = ohci_hcd_omap_drv_remove,

Просмотреть файл

@ -112,23 +112,13 @@ ohci_pci_start (struct usb_hcd *hcd)
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); /* root hub was already suspended */
/* suspend root hub, hoping it keeps power during suspend */ /* FIXME these PMAC things get called in the wrong places. ASIC
if (time_before (jiffies, ohci->next_statechange)) * clocks should be turned off AFTER entering D3, and on BEFORE
msleep (100); * trying to enter D0. Evidently the PCI layer doesn't currently
* provide the right sort of platform hooks for this ...
#ifdef CONFIG_USB_SUSPEND */
(void) usb_suspend_device (hcd->self.root_hub, message);
#else
usb_lock_device (hcd->self.root_hub);
(void) ohci_hub_suspend (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
/* let things settle down a bit */
msleep (100);
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
if (_machine == _MACH_Pmac) { if (_machine == _MACH_Pmac) {
struct device_node *of_node; struct device_node *of_node;
@ -145,9 +135,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
static int ohci_pci_resume (struct usb_hcd *hcd) static int ohci_pci_resume (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int retval = 0;
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
if (_machine == _MACH_Pmac) { if (_machine == _MACH_Pmac) {
struct device_node *of_node; struct device_node *of_node;
@ -159,19 +146,8 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
} }
#endif /* CONFIG_PPC_PMAC */ #endif /* CONFIG_PPC_PMAC */
/* resume root hub */ usb_hcd_resume_root_hub(hcd);
if (time_before (jiffies, ohci->next_statechange)) return 0;
msleep (100);
#ifdef CONFIG_USB_SUSPEND
/* get extra cleanup even if remote wakeup isn't in use */
retval = usb_resume_device (hcd->self.root_hub);
#else
usb_lock_device (hcd->self.root_hub);
retval = ohci_hub_resume (hcd);
usb_unlock_device (hcd->self.root_hub);
#endif
return retval;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
@ -218,9 +194,9 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
.hub_suspend = ohci_hub_suspend, .bus_suspend = ohci_bus_suspend,
.hub_resume = ohci_hub_resume, .bus_resume = ohci_bus_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset, .start_port_reset = ohci_start_port_reset,
}; };
@ -240,6 +216,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
static struct pci_driver ohci_pci_driver = { static struct pci_driver ohci_pci_driver = {
.name = (char *) hcd_name, .name = (char *) hcd_name,
.id_table = pci_ids, .id_table = pci_ids,
.owner = THIS_MODULE,
.probe = usb_hcd_pci_probe, .probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove, .remove = usb_hcd_pci_remove,

Просмотреть файл

@ -163,9 +163,9 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
.hub_suspend = ohci_hub_suspend, .bus_suspend = ohci_bus_suspend,
.hub_resume = ohci_hub_resume, .bus_resume = ohci_bus_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset, .start_port_reset = ohci_start_port_reset,
}; };
@ -193,10 +193,11 @@ static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
static struct device_driver ohci_hcd_ppc_soc_driver = { static struct device_driver ohci_hcd_ppc_soc_driver = {
.name = "ppc-soc-ohci", .name = "ppc-soc-ohci",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = ohci_hcd_ppc_soc_drv_probe, .probe = ohci_hcd_ppc_soc_drv_probe,
.remove = ohci_hcd_ppc_soc_drv_remove, .remove = ohci_hcd_ppc_soc_drv_remove,
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) #ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
#endif #endif

Просмотреть файл

@ -278,10 +278,11 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
.hub_suspend = ohci_hub_suspend, .bus_suspend = ohci_bus_suspend,
.hub_resume = ohci_hub_resume, .bus_resume = ohci_bus_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/

Просмотреть файл

@ -448,11 +448,11 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/ */
.hub_status_data = ohci_s3c2410_hub_status_data, .hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control, .hub_control = ohci_s3c2410_hub_control,
#ifdef CONFIG_PM
#if defined(CONFIG_USB_SUSPEND) && 0 .bus_suspend = ohci_bus_suspend,
.hub_suspend = ohci_hub_suspend, .bus_resume = ohci_bus_resume,
.hub_resume = ohci_hub_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset,
}; };
/* device driver */ /* device driver */
@ -474,6 +474,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct device *dev)
static struct device_driver ohci_hcd_s3c2410_driver = { static struct device_driver ohci_hcd_s3c2410_driver = {
.name = "s3c2410-ohci", .name = "s3c2410-ohci",
.owner = THIS_MODULE,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = ohci_hcd_s3c2410_drv_probe, .probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove, .remove = ohci_hcd_s3c2410_drv_remove,

Просмотреть файл

@ -235,10 +235,11 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/ */
.hub_status_data = ohci_hub_status_data, .hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control, .hub_control = ohci_hub_control,
#ifdef CONFIG_USB_SUSPEND #ifdef CONFIG_PM
.hub_suspend = ohci_hub_suspend, .bus_suspend = ohci_bus_suspend,
.hub_resume = ohci_hub_resume, .bus_resume = ohci_bus_resume,
#endif #endif
.start_port_reset = ohci_start_port_reset,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/

Просмотреть файл

@ -389,7 +389,6 @@ struct ohci_hcd {
unsigned long next_statechange; /* suspend/resume */ unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */ u32 fminterval; /* saved register */
struct work_struct rh_resume;
struct notifier_block reboot_notifier; struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */ unsigned long flags; /* for HC bugs */

Просмотреть файл

@ -0,0 +1,296 @@
/*
* This file contains code to reset and initialize USB host controllers.
* Some of it includes work-arounds for PCI hardware and BIOS quirks.
* It may need to run early during booting -- before USB would normally
* initialize -- to ensure that Linux doesn't use any legacy modes.
*
* Copyright (c) 1999 Martin Mares <mj@ucw.cz>
* (and others)
*/
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/acpi.h>
#define UHCI_USBLEGSUP 0xc0 /* legacy support */
#define UHCI_USBCMD 0 /* command register */
#define UHCI_USBINTR 4 /* interrupt register */
#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
#define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */
#define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */
#define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */
#define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */
#define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */
#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_RWC (1 << 9) /* remote wakeup connected */
#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 */
/*
* Make sure the controller is completely inactive, unable to
* generate interrupts or do DMA.
*/
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base)
{
/* Turn off PIRQ enable and SMI enable. (This also turns off the
* BIOS's USB Legacy Support.) Turn off all the R/WC bits too.
*/
pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC);
/* Reset the HC - this will force us to get a
* new notification of any already connected
* ports due to the virtual disconnect that it
* implies.
*/
outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD);
mb();
udelay(5);
if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET)
dev_warn(&pdev->dev, "HCRESET not completed yet!\n");
/* Just to be safe, disable interrupt requests and
* make sure the controller is stopped.
*/
outw(0, base + UHCI_USBINTR);
outw(0, base + UHCI_USBCMD);
}
EXPORT_SYMBOL_GPL(uhci_reset_hc);
/*
* Initialize a controller that was newly discovered or has just been
* resumed. In either case we can't be sure of its previous state.
*
* Returns: 1 if the controller was reset, 0 otherwise.
*/
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
{
u16 legsup;
unsigned int cmd, intr;
/*
* When restarting a suspended controller, we expect all the
* settings to be the same as we left them:
*
* PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
* Controller is stopped and configured with EGSM set;
* No interrupts enabled except possibly Resume Detect.
*
* If any of these conditions are violated we do a complete reset.
*/
pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup);
if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) {
dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n",
__FUNCTION__, legsup);
goto reset_needed;
}
cmd = inw(base + UHCI_USBCMD);
if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) ||
!(cmd & UHCI_USBCMD_EGSM)) {
dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n",
__FUNCTION__, cmd);
goto reset_needed;
}
intr = inw(base + UHCI_USBINTR);
if (intr & (~UHCI_USBINTR_RESUME)) {
dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n",
__FUNCTION__, intr);
goto reset_needed;
}
return 0;
reset_needed:
dev_dbg(&pdev->dev, "Performing full reset\n");
uhci_reset_hc(pdev, base);
return 1;
}
EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
{
unsigned long base = 0;
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)
uhci_check_and_reset_hc(pdev, base);
}
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
int wait_time;
u32 control;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL) return;
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
#ifndef __hppa__
control = readl(base + OHCI_CONTROL);
if (control & OHCI_CTRL_IR) {
wait_time = 500; /* arbitrary; 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);
}
if (wait_time <= 0)
printk(KERN_WARNING "%s %s: early BIOS handoff "
"failed (BIOS bug ?)\n",
pdev->dev.bus_id, "OHCI");
/* reset controller, preserving RWC */
writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
}
#endif
/*
* 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 "%s %s: early BIOS handoff "
"failed (BIOS bug ?)\n",
pdev->dev.bus_id, "EHCI");
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 (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
quirk_usb_handoff_uhci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
quirk_usb_handoff_ohci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
quirk_usb_disable_ehci(pdev);
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);

Просмотреть файл

@ -1363,7 +1363,7 @@ error:
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int static int
sl811h_hub_suspend(struct usb_hcd *hcd) sl811h_bus_suspend(struct usb_hcd *hcd)
{ {
// SOFs off // SOFs off
DBG("%s\n", __FUNCTION__); DBG("%s\n", __FUNCTION__);
@ -1371,7 +1371,7 @@ sl811h_hub_suspend(struct usb_hcd *hcd)
} }
static int static int
sl811h_hub_resume(struct usb_hcd *hcd) sl811h_bus_resume(struct usb_hcd *hcd)
{ {
// SOFs on // SOFs on
DBG("%s\n", __FUNCTION__); DBG("%s\n", __FUNCTION__);
@ -1380,8 +1380,8 @@ sl811h_hub_resume(struct usb_hcd *hcd)
#else #else
#define sl811h_hub_suspend NULL #define sl811h_bus_suspend NULL
#define sl811h_hub_resume NULL #define sl811h_bus_resume NULL
#endif #endif
@ -1623,8 +1623,8 @@ static struct hc_driver sl811h_hc_driver = {
*/ */
.hub_status_data = sl811h_hub_status_data, .hub_status_data = sl811h_hub_status_data,
.hub_control = sl811h_hub_control, .hub_control = sl811h_hub_control,
.hub_suspend = sl811h_hub_suspend, .bus_suspend = sl811h_bus_suspend,
.hub_resume = sl811h_hub_resume, .bus_resume = sl811h_bus_resume,
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -1791,7 +1791,7 @@ sl811h_suspend(struct device *dev, pm_message_t state)
int retval = 0; int retval = 0;
if (state.event == PM_EVENT_FREEZE) if (state.event == PM_EVENT_FREEZE)
retval = sl811h_hub_suspend(hcd); retval = sl811h_bus_suspend(hcd);
else if (state.event == PM_EVENT_SUSPEND) else if (state.event == PM_EVENT_SUSPEND)
port_power(sl811, 0); port_power(sl811, 0);
if (retval == 0) if (retval == 0)
@ -1816,7 +1816,7 @@ sl811h_resume(struct device *dev)
} }
dev->power.power_state = PMSG_ON; dev->power.power_state = PMSG_ON;
return sl811h_hub_resume(hcd); return sl811h_bus_resume(hcd);
} }
#else #else
@ -1831,6 +1831,7 @@ sl811h_resume(struct device *dev)
struct device_driver sl811h_driver = { struct device_driver sl811h_driver = {
.name = (char *) hcd_name, .name = (char *) hcd_name,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.owner = THIS_MODULE,
.probe = sl811h_probe, .probe = sl811h_probe,
.remove = __devexit_p(sl811h_remove), .remove = __devexit_p(sl811h_remove),

Просмотреть файл

@ -348,7 +348,6 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu
if (urbp->urb->status != -EINPROGRESS) if (urbp->urb->status != -EINPROGRESS)
out += sprintf(out, "Status=%d ", urbp->urb->status); out += sprintf(out, "Status=%d ", urbp->urb->status);
//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
count = 0; count = 0;
@ -446,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
out += sprintf(out, "Frame List\n"); out += sprintf(out, "Frame List\n");
for (i = 0; i < UHCI_NUMFRAMES; ++i) { for (i = 0; i < UHCI_NUMFRAMES; ++i) {
int shown = 0; int shown = 0;
td = uhci->fl->frame_cpu[i]; td = uhci->frame_cpu[i];
if (!td) if (!td)
continue; continue;
if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) { if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
show_frame_num(); show_frame_num();
out += sprintf(out, " frame list does not match td->dma_handle!\n"); out += sprintf(out, " frame list does not match td->dma_handle!\n");
} }

Просмотреть файл

@ -101,37 +101,16 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
#include "uhci-q.c" #include "uhci-q.c"
#include "uhci-hub.c" #include "uhci-hub.c"
extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
/* /*
* Make sure the controller is completely inactive, unable to * Finish up a host controller reset and update the recorded state.
* generate interrupts or do DMA.
*/ */
static void reset_hc(struct uhci_hcd *uhci) static void finish_reset(struct uhci_hcd *uhci)
{ {
int port; int port;
/* Turn off PIRQ enable and SMI enable. (This also turns off the
* BIOS's USB Legacy Support.) Turn off all the R/WC bits too.
*/
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_RWC);
/* Reset the HC - this will force us to get a
* new notification of any already connected
* ports due to the virtual disconnect that it
* implies.
*/
outw(USBCMD_HCRESET, uhci->io_addr + USBCMD);
mb();
udelay(5);
if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET)
dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
/* Just to be safe, disable interrupt requests and
* make sure the controller is stopped.
*/
outw(0, uhci->io_addr + USBINTR);
outw(0, uhci->io_addr + USBCMD);
/* HCRESET doesn't affect the Suspend, Reset, and Resume Detect /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
* bits in the port status and control registers. * bits in the port status and control registers.
* We have to clear them by hand. * We have to clear them by hand.
@ -153,7 +132,8 @@ static void reset_hc(struct uhci_hcd *uhci)
*/ */
static void hc_died(struct uhci_hcd *uhci) static void hc_died(struct uhci_hcd *uhci)
{ {
reset_hc(uhci); uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
finish_reset(uhci);
uhci->hc_inaccessible = 1; uhci->hc_inaccessible = 1;
} }
@ -163,44 +143,8 @@ static void hc_died(struct uhci_hcd *uhci)
*/ */
static void check_and_reset_hc(struct uhci_hcd *uhci) static void check_and_reset_hc(struct uhci_hcd *uhci)
{ {
u16 legsup; if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
unsigned int cmd, intr; finish_reset(uhci);
/*
* When restarting a suspended controller, we expect all the
* settings to be the same as we left them:
*
* PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
* Controller is stopped and configured with EGSM set;
* No interrupts enabled except possibly Resume Detect.
*
* If any of these conditions are violated we do a complete reset.
*/
pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup);
if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) {
dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n",
__FUNCTION__, legsup);
goto reset_needed;
}
cmd = inw(uhci->io_addr + USBCMD);
if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
__FUNCTION__, cmd);
goto reset_needed;
}
intr = inw(uhci->io_addr + USBINTR);
if (intr & (~USBINTR_RESUME)) {
dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
__FUNCTION__, intr);
goto reset_needed;
}
return;
reset_needed:
dev_dbg(uhci_dev(uhci), "Performing full reset\n");
reset_hc(uhci);
} }
/* /*
@ -212,13 +156,13 @@ static void configure_hc(struct uhci_hcd *uhci)
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
/* Store the frame list base address */ /* Store the frame list base address */
outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
/* Set the current frame number */ /* Set the current frame number */
outw(uhci->frame_number, uhci->io_addr + USBFRNUM); outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
/* Mark controller as running before we enable interrupts */ /* Mark controller as not halted before we enable interrupts */
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
mb(); mb();
/* Enable PIRQ */ /* Enable PIRQ */
@ -319,6 +263,7 @@ __acquires(uhci->lock)
static void start_rh(struct uhci_hcd *uhci) static void start_rh(struct uhci_hcd *uhci)
{ {
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
uhci->is_stopped = 0; uhci->is_stopped = 0;
smp_wmb(); smp_wmb();
@ -437,36 +382,21 @@ static void release_uhci(struct uhci_hcd *uhci)
int i; int i;
for (i = 0; i < UHCI_NUM_SKELQH; i++) for (i = 0; i < UHCI_NUM_SKELQH; i++)
if (uhci->skelqh[i]) { uhci_free_qh(uhci, uhci->skelqh[i]);
uhci_free_qh(uhci, uhci->skelqh[i]);
uhci->skelqh[i] = NULL;
}
if (uhci->term_td) { uhci_free_td(uhci, uhci->term_td);
uhci_free_td(uhci, uhci->term_td);
uhci->term_td = NULL;
}
if (uhci->qh_pool) { dma_pool_destroy(uhci->qh_pool);
dma_pool_destroy(uhci->qh_pool);
uhci->qh_pool = NULL;
}
if (uhci->td_pool) { dma_pool_destroy(uhci->td_pool);
dma_pool_destroy(uhci->td_pool);
uhci->td_pool = NULL;
}
if (uhci->fl) { kfree(uhci->frame_cpu);
dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
uhci->fl, uhci->fl->dma_handle);
uhci->fl = NULL;
}
if (uhci->dentry) { dma_free_coherent(uhci_dev(uhci),
debugfs_remove(uhci->dentry); UHCI_NUMFRAMES * sizeof(*uhci->frame),
uhci->dentry = NULL; uhci->frame, uhci->frame_dma_handle);
}
debugfs_remove(uhci->dentry);
} }
static int uhci_reset(struct usb_hcd *hcd) static int uhci_reset(struct usb_hcd *hcd)
@ -545,7 +475,6 @@ static int uhci_start(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int retval = -EBUSY; int retval = -EBUSY;
int i; int i;
dma_addr_t dma_handle;
struct dentry *dentry; struct dentry *dentry;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
@ -579,17 +508,23 @@ static int uhci_start(struct usb_hcd *hcd)
init_waitqueue_head(&uhci->waitqh); init_waitqueue_head(&uhci->waitqh);
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
&dma_handle, 0); UHCI_NUMFRAMES * sizeof(*uhci->frame),
if (!uhci->fl) { &uhci->frame_dma_handle, 0);
if (!uhci->frame) {
dev_err(uhci_dev(uhci), "unable to allocate " dev_err(uhci_dev(uhci), "unable to allocate "
"consistent memory for frame list\n"); "consistent memory for frame list\n");
goto err_alloc_fl; goto err_alloc_frame;
} }
memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame));
memset((void *)uhci->fl, 0, sizeof(*uhci->fl)); uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu),
GFP_KERNEL);
uhci->fl->dma_handle = dma_handle; if (!uhci->frame_cpu) {
dev_err(uhci_dev(uhci), "unable to allocate "
"memory for frame pointers\n");
goto err_alloc_frame_cpu;
}
uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci), uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
sizeof(struct uhci_td), 16, 0); sizeof(struct uhci_td), 16, 0);
@ -672,7 +607,7 @@ static int uhci_start(struct usb_hcd *hcd)
irq = 7; irq = 7;
/* Only place we don't use the frame list routines */ /* Only place we don't use the frame list routines */
uhci->fl->frame[i] = UHCI_PTR_QH | uhci->frame[i] = UHCI_PTR_QH |
cpu_to_le32(uhci->skelqh[irq]->dma_handle); cpu_to_le32(uhci->skelqh[irq]->dma_handle);
} }
@ -690,31 +625,29 @@ static int uhci_start(struct usb_hcd *hcd)
* error exits: * error exits:
*/ */
err_alloc_skelqh: err_alloc_skelqh:
for (i = 0; i < UHCI_NUM_SKELQH; i++) for (i = 0; i < UHCI_NUM_SKELQH; i++) {
if (uhci->skelqh[i]) { if (uhci->skelqh[i])
uhci_free_qh(uhci, uhci->skelqh[i]); uhci_free_qh(uhci, uhci->skelqh[i]);
uhci->skelqh[i] = NULL; }
}
uhci_free_td(uhci, uhci->term_td); uhci_free_td(uhci, uhci->term_td);
uhci->term_td = NULL;
err_alloc_term_td: err_alloc_term_td:
dma_pool_destroy(uhci->qh_pool); dma_pool_destroy(uhci->qh_pool);
uhci->qh_pool = NULL;
err_create_qh_pool: err_create_qh_pool:
dma_pool_destroy(uhci->td_pool); dma_pool_destroy(uhci->td_pool);
uhci->td_pool = NULL;
err_create_td_pool: err_create_td_pool:
dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl), kfree(uhci->frame_cpu);
uhci->fl, uhci->fl->dma_handle);
uhci->fl = NULL;
err_alloc_fl: err_alloc_frame_cpu:
dma_free_coherent(uhci_dev(uhci),
UHCI_NUMFRAMES * sizeof(*uhci->frame),
uhci->frame, uhci->frame_dma_handle);
err_alloc_frame:
debugfs_remove(uhci->dentry); debugfs_remove(uhci->dentry);
uhci->dentry = NULL;
err_create_debug_entry: err_create_debug_entry:
return retval; return retval;
@ -726,7 +659,7 @@ static void uhci_stop(struct usb_hcd *hcd)
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
if (!uhci->hc_inaccessible) if (!uhci->hc_inaccessible)
reset_hc(uhci); hc_died(uhci);
uhci_scan_schedule(uhci, NULL); uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
@ -774,14 +707,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
if (uhci->hc_inaccessible) /* Dead or already suspended */ if (uhci->hc_inaccessible) /* Dead or already suspended */
goto done; goto done;
#ifndef CONFIG_USB_SUSPEND
/* Otherwise this would never happen */
suspend_rh(uhci, UHCI_RH_SUSPENDED);
#endif
if (uhci->rh_state > UHCI_RH_SUSPENDED) { if (uhci->rh_state > UHCI_RH_SUSPENDED) {
dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
hcd->state = HC_STATE_RUNNING;
rc = -EBUSY; rc = -EBUSY;
goto done; goto done;
}; };
@ -820,10 +747,6 @@ static int uhci_resume(struct usb_hcd *hcd)
check_and_reset_hc(uhci); check_and_reset_hc(uhci);
configure_hc(uhci); configure_hc(uhci);
#ifndef CONFIG_USB_SUSPEND
/* Otherwise this would never happen */
wakeup_rh(uhci);
#endif
if (uhci->rh_state == UHCI_RH_RESET) if (uhci->rh_state == UHCI_RH_RESET)
suspend_rh(uhci, UHCI_RH_SUSPENDED); suspend_rh(uhci, UHCI_RH_SUSPENDED);
@ -881,8 +804,8 @@ static const struct hc_driver uhci_driver = {
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = uhci_suspend, .suspend = uhci_suspend,
.resume = uhci_resume, .resume = uhci_resume,
.hub_suspend = uhci_rh_suspend, .bus_suspend = uhci_rh_suspend,
.hub_resume = uhci_rh_resume, .bus_resume = uhci_rh_resume,
#endif #endif
.stop = uhci_stop, .stop = uhci_stop,
@ -908,6 +831,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
static struct pci_driver uhci_pci_driver = { static struct pci_driver uhci_pci_driver = {
.name = (char *)hcd_name, .name = (char *)hcd_name,
.id_table = uhci_pci_ids, .id_table = uhci_pci_ids,
.owner = THIS_MODULE,
.probe = usb_hcd_pci_probe, .probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove, .remove = usb_hcd_pci_remove,

Просмотреть файл

@ -7,6 +7,7 @@
#define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT) #define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
#define PIPE_DEVEP_MASK 0x0007ff00 #define PIPE_DEVEP_MASK 0x0007ff00
/* /*
* Universal Host Controller Interface data structures and defines * Universal Host Controller Interface data structures and defines
*/ */
@ -82,15 +83,10 @@
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ #define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
struct uhci_frame_list {
__le32 frame[UHCI_NUMFRAMES];
void *frame_cpu[UHCI_NUMFRAMES]; /*
* Queue Headers
dma_addr_t dma_handle; */
};
struct urb_priv;
/* /*
* One role of a QH is to hold a queue of TDs for some endpoint. Each QH is * One role of a QH is to hold a queue of TDs for some endpoint. Each QH is
@ -116,13 +112,13 @@ struct uhci_qh {
struct urb_priv *urbp; struct urb_priv *urbp;
struct list_head list; /* P: uhci->frame_list_lock */ struct list_head list;
struct list_head remove_list; /* P: uhci->remove_list_lock */ struct list_head remove_list;
} __attribute__((aligned(16))); } __attribute__((aligned(16)));
/* /*
* We need a special accessor for the element pointer because it is * We need a special accessor for the element pointer because it is
* subject to asynchronous updates by the controller * subject to asynchronous updates by the controller.
*/ */
static __le32 inline qh_element(struct uhci_qh *qh) { static __le32 inline qh_element(struct uhci_qh *qh) {
__le32 element = qh->element; __le32 element = qh->element;
@ -131,6 +127,11 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
return element; return element;
} }
/*
* Transfer Descriptors
*/
/* /*
* for TD <status>: * for TD <status>:
*/ */
@ -183,17 +184,10 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
* *
* That's silly, the hardware doesn't care. The hardware only cares that * That's silly, the hardware doesn't care. The hardware only cares that
* the hardware words are 16-byte aligned, and we can have any amount of * the hardware words are 16-byte aligned, and we can have any amount of
* sw space after the TD entry as far as I can tell. * sw space after the TD entry.
*
* But let's just go with the documentation, at least for 32-bit machines.
* On 64-bit machines we probably want to take advantage of the fact that
* hw doesn't really care about the size of the sw-only area.
*
* Alas, not anymore, we have more than 4 words for software, woops.
* Everything still works tho, surprise! -jerdfelt
* *
* td->link points to either another TD (not necessarily for the same urb or * td->link points to either another TD (not necessarily for the same urb or
* even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs) * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
*/ */
struct uhci_td { struct uhci_td {
/* Hardware fields */ /* Hardware fields */
@ -205,18 +199,16 @@ struct uhci_td {
/* Software fields */ /* Software fields */
dma_addr_t dma_handle; dma_addr_t dma_handle;
struct urb *urb; struct list_head list;
struct list_head remove_list;
struct list_head list; /* P: urb->lock */
struct list_head remove_list; /* P: uhci->td_remove_list_lock */
int frame; /* for iso: what frame? */ int frame; /* for iso: what frame? */
struct list_head fl_list; /* P: uhci->frame_list_lock */ struct list_head fl_list;
} __attribute__((aligned(16))); } __attribute__((aligned(16)));
/* /*
* We need a special accessor for the control/status word because it is * We need a special accessor for the control/status word because it is
* subject to asynchronous updates by the controller * subject to asynchronous updates by the controller.
*/ */
static u32 inline td_status(struct uhci_td *td) { static u32 inline td_status(struct uhci_td *td) {
__le32 status = td->status; __le32 status = td->status;
@ -226,6 +218,10 @@ static u32 inline td_status(struct uhci_td *td) {
} }
/*
* Skeleton Queue Headers
*/
/* /*
* The UHCI driver places Interrupt, Control and Bulk into QH's both * The UHCI driver places Interrupt, Control and Bulk into QH's both
* to group together TD's for one transfer, and also to faciliate queuing * to group together TD's for one transfer, and also to faciliate queuing
@ -256,15 +252,15 @@ static u32 inline td_status(struct uhci_td *td) {
* *
* The terminating QH is used for 2 reasons: * The terminating QH is used for 2 reasons:
* - To place a terminating TD which is used to workaround a PIIX bug * - To place a terminating TD which is used to workaround a PIIX bug
* (see Intel errata for explanation) * (see Intel errata for explanation), and
* - To loop back to the full-speed control queue for full-speed bandwidth * - To loop back to the full-speed control queue for full-speed bandwidth
* reclamation * reclamation.
* *
* Isochronous transfers are stored before the start of the skeleton * Isochronous transfers are stored before the start of the skeleton
* schedule and don't use QH's. While the UHCI spec doesn't forbid the * schedule and don't use QH's. While the UHCI spec doesn't forbid the
* use of QH's for Isochronous, it doesn't use them either. Since we don't * use of QH's for Isochronous, it doesn't use them either. And the spec
* need to use them either, we follow the spec diagrams in hope that it'll * says that queues never advance on an error completion status, which
* be more compatible with future UHCI implementations. * makes them totally unsuitable for Isochronous transfers.
*/ */
#define UHCI_NUM_SKELQH 12 #define UHCI_NUM_SKELQH 12
@ -314,8 +310,13 @@ static inline int __interval_to_skel(int interval)
return 0; /* int128 for 128-255 ms (Max.) */ return 0; /* int128 for 128-255 ms (Max.) */
} }
/* /*
* States for the root hub. * The UHCI controller and root hub
*/
/*
* States for the root hub:
* *
* To prevent "bouncing" in the presence of electrical noise, * To prevent "bouncing" in the presence of electrical noise,
* when there are no devices attached we delay for 1 second in the * when there are no devices attached we delay for 1 second in the
@ -326,7 +327,7 @@ static inline int __interval_to_skel(int interval)
*/ */
enum uhci_rh_state { enum uhci_rh_state {
/* In the following states the HC must be halted. /* In the following states the HC must be halted.
* These two must come first */ * These two must come first. */
UHCI_RH_RESET, UHCI_RH_RESET,
UHCI_RH_SUSPENDED, UHCI_RH_SUSPENDED,
@ -338,13 +339,13 @@ enum uhci_rh_state {
UHCI_RH_SUSPENDING, UHCI_RH_SUSPENDING,
/* In the following states it's an error if the HC is halted. /* In the following states it's an error if the HC is halted.
* These two must come last */ * These two must come last. */
UHCI_RH_RUNNING, /* The normal state */ UHCI_RH_RUNNING, /* The normal state */
UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */
}; };
/* /*
* This describes the full uhci information. * The full UHCI controller information:
*/ */
struct uhci_hcd { struct uhci_hcd {
@ -361,7 +362,11 @@ struct uhci_hcd {
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
spinlock_t lock; spinlock_t lock;
struct uhci_frame_list *fl; /* P: uhci->lock */
dma_addr_t frame_dma_handle; /* Hardware frame list */
__le32 *frame;
void **frame_cpu; /* CPU's frame list */
int fsbr; /* Full-speed bandwidth reclamation */ int fsbr; /* Full-speed bandwidth reclamation */
unsigned long fsbrtimeout; /* FSBR delay */ unsigned long fsbrtimeout; /* FSBR delay */
@ -385,22 +390,22 @@ struct uhci_hcd {
unsigned long ports_timeout; /* Time to stop signalling */ unsigned long ports_timeout; /* Time to stop signalling */
/* Main list of URB's currently controlled by this HC */ /* Main list of URB's currently controlled by this HC */
struct list_head urb_list; /* P: uhci->lock */ struct list_head urb_list;
/* List of QH's that are done, but waiting to be unlinked (race) */ /* List of QH's that are done, but waiting to be unlinked (race) */
struct list_head qh_remove_list; /* P: uhci->lock */ struct list_head qh_remove_list;
unsigned int qh_remove_age; /* Age in frames */ unsigned int qh_remove_age; /* Age in frames */
/* List of TD's that are done, but waiting to be freed (race) */ /* List of TD's that are done, but waiting to be freed (race) */
struct list_head td_remove_list; /* P: uhci->lock */ struct list_head td_remove_list;
unsigned int td_remove_age; /* Age in frames */ unsigned int td_remove_age; /* Age in frames */
/* List of asynchronously unlinked URB's */ /* List of asynchronously unlinked URB's */
struct list_head urb_remove_list; /* P: uhci->lock */ struct list_head urb_remove_list;
unsigned int urb_remove_age; /* Age in frames */ unsigned int urb_remove_age; /* Age in frames */
/* List of URB's awaiting completion callback */ /* List of URB's awaiting completion callback */
struct list_head complete_list; /* P: uhci->lock */ struct list_head complete_list;
int rh_numports; /* Number of root-hub ports */ int rh_numports; /* Number of root-hub ports */
@ -419,13 +424,17 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
#define uhci_dev(u) (uhci_to_hcd(u)->self.controller) #define uhci_dev(u) (uhci_to_hcd(u)->self.controller)
/*
* Private per-URB data
*/
struct urb_priv { struct urb_priv {
struct list_head urb_list; struct list_head urb_list;
struct urb *urb; struct urb *urb;
struct uhci_qh *qh; /* QH for this URB */ struct uhci_qh *qh; /* QH for this URB */
struct list_head td_list; /* P: urb->lock */ struct list_head td_list;
unsigned fsbr : 1; /* URB turned on FSBR */ unsigned fsbr : 1; /* URB turned on FSBR */
unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ unsigned fsbr_timeout : 1; /* URB timed out on FSBR */
@ -434,12 +443,12 @@ struct urb_priv {
/* a control transfer, retrigger */ /* a control transfer, retrigger */
/* the status phase */ /* the status phase */
unsigned long inserttime; /* In jiffies */
unsigned long fsbrtime; /* In jiffies */ unsigned long fsbrtime; /* In jiffies */
struct list_head queue_list; /* P: uhci->frame_list_lock */ struct list_head queue_list;
}; };
/* /*
* Locking in uhci.c * Locking in uhci.c
* *
@ -459,6 +468,5 @@ struct urb_priv {
#define PCI_VENDOR_ID_GENESYS 0x17a0 #define PCI_VENDOR_ID_GENESYS 0x17a0
#define PCI_DEVICE_ID_GL880S_UHCI 0x8083 #define PCI_DEVICE_ID_GL880S_UHCI 0x8083
#define PCI_DEVICE_ID_GL880S_EHCI 0x8084
#endif #endif

Просмотреть файл

@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
td->frame = framenum; td->frame = framenum;
/* Is there a TD already mapped there? */ /* Is there a TD already mapped there? */
if (uhci->fl->frame_cpu[framenum]) { if (uhci->frame_cpu[framenum]) {
struct uhci_td *ftd, *ltd; struct uhci_td *ftd, *ltd;
ftd = uhci->fl->frame_cpu[framenum]; ftd = uhci->frame_cpu[framenum];
ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
list_add_tail(&td->fl_list, &ftd->fl_list); list_add_tail(&td->fl_list, &ftd->fl_list);
@ -101,29 +101,32 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
wmb(); wmb();
ltd->link = cpu_to_le32(td->dma_handle); ltd->link = cpu_to_le32(td->dma_handle);
} else { } else {
td->link = uhci->fl->frame[framenum]; td->link = uhci->frame[framenum];
wmb(); wmb();
uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
uhci->fl->frame_cpu[framenum] = td; uhci->frame_cpu[framenum] = td;
} }
} }
static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
struct uhci_td *td)
{ {
/* If it's not inserted, don't remove it */ /* If it's not inserted, don't remove it */
if (td->frame == -1 && list_empty(&td->fl_list)) if (td->frame == -1) {
WARN_ON(!list_empty(&td->fl_list));
return; return;
}
if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (uhci->frame_cpu[td->frame] == td) {
if (list_empty(&td->fl_list)) { if (list_empty(&td->fl_list)) {
uhci->fl->frame[td->frame] = td->link; uhci->frame[td->frame] = td->link;
uhci->fl->frame_cpu[td->frame] = NULL; uhci->frame_cpu[td->frame] = NULL;
} else { } else {
struct uhci_td *ntd; struct uhci_td *ntd;
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
uhci->fl->frame_cpu[td->frame] = ntd; uhci->frame_cpu[td->frame] = ntd;
} }
} else { } else {
struct uhci_td *ptd; struct uhci_td *ptd;
@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
ptd->link = td->link; ptd->link = td->link;
} }
wmb();
td->link = UHCI_PTR_TERM;
list_del_init(&td->fl_list); list_del_init(&td->fl_list);
td->frame = -1; td->frame = -1;
} }
static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
struct uhci_td *td;
list_for_each_entry(td, &urbp->td_list, list)
uhci_remove_td_frame_list(uhci, td);
wmb();
}
/* /*
* Inserts a td list into qh. * Inserts a td list into qh.
*/ */
@ -443,7 +453,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u
memset((void *)urbp, 0, sizeof(*urbp)); memset((void *)urbp, 0, sizeof(*urbp));
urbp->inserttime = jiffies;
urbp->fsbrtime = jiffies; urbp->fsbrtime = jiffies;
urbp->urb = urb; urbp->urb = urb;
@ -462,8 +471,6 @@ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
{ {
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
td->urb = urb;
list_add_tail(&td->list, &urbp->td_list); list_add_tail(&td->list, &urbp->td_list);
} }
@ -473,8 +480,6 @@ static void uhci_remove_td_from_urb(struct uhci_td *td)
return; return;
list_del_init(&td->list); list_del_init(&td->list);
td->urb = NULL;
} }
static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
@ -503,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
uhci_remove_td_from_urb(td); uhci_remove_td_from_urb(td);
uhci_remove_td(uhci, td);
list_add(&td->remove_list, &uhci->td_remove_list); list_add(&td->remove_list, &uhci->td_remove_list);
} }
@ -1073,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
struct uhci_td *td; struct uhci_td *td;
int i, ret, frame; int i, ret, frame;
int status, destination; int status, destination;
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
status = TD_CTRL_ACTIVE | TD_CTRL_IOS; status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@ -1081,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
if (ret) if (ret)
return ret; return ret;
frame = urb->start_frame; for (i = 0; i < urb->number_of_packets; i++) {
for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
if (!urb->iso_frame_desc[i].length)
continue;
td = uhci_alloc_td(uhci); td = uhci_alloc_td(uhci);
if (!td) if (!td)
return -ENOMEM; return -ENOMEM;
@ -1096,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
if (i + 1 >= urb->number_of_packets) if (i + 1 >= urb->number_of_packets)
td->status |= cpu_to_le32(TD_CTRL_IOC); td->status |= cpu_to_le32(TD_CTRL_IOC);
}
frame = urb->start_frame;
list_for_each_entry(td, &urbp->td_list, list) {
uhci_insert_td_frame_list(uhci, td, frame); uhci_insert_td_frame_list(uhci, td, frame);
frame += urb->interval;
} }
return -EINPROGRESS; return -EINPROGRESS;
@ -1110,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
int status; int status;
int i, ret = 0; int i, ret = 0;
urb->actual_length = 0; urb->actual_length = urb->error_count = 0;
i = 0; i = 0;
list_for_each_entry(td, &urbp->td_list, list) { list_for_each_entry(td, &urbp->td_list, list) {
@ -1134,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
i++; i++;
} }
unlink_isochronous_tds(uhci, urb);
return ret; return ret;
} }
@ -1366,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
goto done; goto done;
list_del_init(&urbp->urb_list); list_del_init(&urbp->urb_list);
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
unlink_isochronous_tds(uhci, urb);
uhci_unlink_generic(uhci, urb); uhci_unlink_generic(uhci, urb);
uhci_get_current_frame_number(uhci); uhci_get_current_frame_number(uhci);

Просмотреть файл

@ -425,9 +425,8 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
static struct usb_driver mdc800_usb_driver; static struct usb_driver mdc800_usb_driver;
static struct file_operations mdc800_device_ops; static struct file_operations mdc800_device_ops;
static struct usb_class_driver mdc800_class = { static struct usb_class_driver mdc800_class = {
.name = "usb/mdc800%d", .name = "mdc800%d",
.fops = &mdc800_device_ops, .fops = &mdc800_device_ops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
.minor_base = MDC800_DEVICE_MINOR_BASE, .minor_base = MDC800_DEVICE_MINOR_BASE,
}; };
@ -976,13 +975,13 @@ static struct usb_driver mdc800_usb_driver =
Init and Cleanup this driver (Main Functions) Init and Cleanup this driver (Main Functions)
*************************************************************************/ *************************************************************************/
#define try(A) if (!(A)) goto cleanup_on_fail;
static int __init usb_mdc800_init (void) static int __init usb_mdc800_init (void)
{ {
int retval = -ENODEV; int retval = -ENODEV;
/* Allocate Memory */ /* Allocate Memory */
try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
if (!mdc800)
goto cleanup_on_fail;
memset(mdc800, 0, sizeof(struct mdc800_data)); memset(mdc800, 0, sizeof(struct mdc800_data));
mdc800->dev = NULL; mdc800->dev = NULL;
@ -998,13 +997,25 @@ static int __init usb_mdc800_init (void)
mdc800->downloaded = 0; mdc800->downloaded = 0;
mdc800->written = 0; mdc800->written = 0;
try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL)); mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL);
try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL)); if (!mdc800->irq_urb_buffer)
try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL)); goto cleanup_on_fail;
mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL);
if (!mdc800->write_urb_buffer)
goto cleanup_on_fail;
mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL);
if (!mdc800->download_urb_buffer)
goto cleanup_on_fail;
try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL)); mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL);
try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL)); if (!mdc800->irq_urb)
try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL)); goto cleanup_on_fail;
mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL);
if (!mdc800->download_urb)
goto cleanup_on_fail;
mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL);
if (!mdc800->write_urb)
goto cleanup_on_fail;
/* Register the driver */ /* Register the driver */
retval = usb_register(&mdc800_usb_driver); retval = usb_register(&mdc800_usb_driver);

Просмотреть файл

@ -773,11 +773,10 @@ static int mts_usb_probe(struct usb_interface *intf,
} }
new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL); new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL);
if (!new_desc) if (!new_desc)
goto out; goto out;
memset(new_desc, 0, sizeof(*new_desc));
new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!new_desc->urb) if (!new_desc->urb)
goto out_kfree; goto out_kfree;

Просмотреть файл

@ -2154,7 +2154,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
* input_handles associated with this input device. * input_handles associated with this input device.
* What identifies an evdev input_handler is that it begins * What identifies an evdev input_handler is that it begins
* with 'event', continues with a digit, and that in turn * with 'event', continues with a digit, and that in turn
* is mapped to /{devfs}/input/eventN. * is mapped to input/eventN.
*/ */
list_for_each_safe(node, next, &inputdev->h_list) { list_for_each_safe(node, next, &inputdev->h_list) {
inputhandle = to_handle(node); inputhandle = to_handle(node);

Просмотреть файл

@ -1784,6 +1784,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
/* May be needed for some devices */
usb_clear_halt(hid->dev, hid->urbin->pipe);
return hid; return hid;
fail: fail:
@ -1887,7 +1890,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
struct hid_device *hid = usb_get_intfdata (intf); struct hid_device *hid = usb_get_intfdata (intf);
usb_kill_urb(hid->urbin); usb_kill_urb(hid->urbin);
intf->dev.power.power_state = PMSG_SUSPEND;
dev_dbg(&intf->dev, "suspend\n"); dev_dbg(&intf->dev, "suspend\n");
return 0; return 0;
} }
@ -1897,7 +1899,6 @@ static int hid_resume(struct usb_interface *intf)
struct hid_device *hid = usb_get_intfdata (intf); struct hid_device *hid = usb_get_intfdata (intf);
int status; int status;
intf->dev.power.power_state = PMSG_ON;
if (hid->open) if (hid->open)
status = usb_submit_urb(hid->urbin, GFP_NOIO); status = usb_submit_urb(hid->urbin, GFP_NOIO);
else else

Просмотреть файл

@ -732,9 +732,8 @@ static struct file_operations hiddev_fops = {
}; };
static struct usb_class_driver hiddev_class = { static struct usb_class_driver hiddev_class = {
.name = "usb/hid/hiddev%d", .name = "hiddev%d",
.fops = &hiddev_fops, .fops = &hiddev_fops,
.mode = S_IFCHR | S_IRUGO | S_IWUSR,
.minor_base = HIDDEV_MINOR_BASE, .minor_base = HIDDEV_MINOR_BASE,
}; };

Просмотреть файл

@ -79,7 +79,7 @@ struct seg7_conversion_map {
static inline int map_to_seg7(struct seg7_conversion_map *map, int c) static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
{ {
return c & 0x7f ? map->table[c] : -EINVAL; return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
} }
#define SEG7_CONVERSION_MAP(_name, _map) \ #define SEG7_CONVERSION_MAP(_name, _map) \

Просмотреть файл

@ -75,7 +75,9 @@ struct touchkit_usb {
static struct usb_device_id touchkit_devices[] = { static struct usb_device_id touchkit_devices[] = {
{USB_DEVICE(0x3823, 0x0001)}, {USB_DEVICE(0x3823, 0x0001)},
{USB_DEVICE(0x0123, 0x0001)},
{USB_DEVICE(0x0eef, 0x0001)}, {USB_DEVICE(0x0eef, 0x0001)},
{USB_DEVICE(0x0eef, 0x0002)},
{} {}
}; };

Просмотреть файл

@ -707,9 +707,8 @@ static struct file_operations dabusb_fops =
}; };
static struct usb_class_driver dabusb_class = { static struct usb_class_driver dabusb_class = {
.name = "usb/dabusb%d", .name = "dabusb%d",
.fops = &dabusb_fops, .fops = &dabusb_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
.minor_base = DABUSB_MINOR, .minor_base = DABUSB_MINOR,
}; };

Просмотреть файл

@ -1873,9 +1873,8 @@ static struct file_operations auerswald_fops =
}; };
static struct usb_class_driver auerswald_class = { static struct usb_class_driver auerswald_class = {
.name = "usb/auer%d", .name = "auer%d",
.fops = &auerswald_fops, .fops = &auerswald_fops,
.mode = S_IFCHR | S_IRUGO | S_IWUGO,
.minor_base = AUER_MINOR_BASE, .minor_base = AUER_MINOR_BASE,
}; };

Просмотреть файл

@ -105,11 +105,10 @@ static struct file_operations idmouse_fops = {
.release = idmouse_release, .release = idmouse_release,
}; };
/* class driver information for devfs */ /* class driver information */
static struct usb_class_driver idmouse_class = { static struct usb_class_driver idmouse_class = {
.name = "usb/idmouse%d", .name = "idmouse%d",
.fops = &idmouse_fops, .fops = &idmouse_fops,
.mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */
.minor_base = USB_IDMOUSE_MINOR_BASE, .minor_base = USB_IDMOUSE_MINOR_BASE,
}; };

Просмотреть файл

@ -271,12 +271,11 @@ static struct file_operations tower_fops = {
/* /*
* usb class driver info in order to get a minor number from the usb core, * usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core * and to have the device registered with the driver core
*/ */
static struct usb_class_driver tower_class = { static struct usb_class_driver tower_class = {
.name = "usb/legousbtower%d", .name = "legousbtower%d",
.fops = &tower_fops, .fops = &tower_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.minor_base = LEGO_USB_TOWER_MINOR_BASE, .minor_base = LEGO_USB_TOWER_MINOR_BASE,
}; };

Просмотреть файл

@ -443,9 +443,8 @@ file_operations usb_rio_fops = {
}; };
static struct usb_class_driver usb_rio_class = { static struct usb_class_driver usb_rio_class = {
.name = "usb/rio500%d", .name = "rio500%d",
.fops = &usb_rio_fops, .fops = &usb_rio_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
.minor_base = RIO_MINOR, .minor_base = RIO_MINOR,
}; };

Просмотреть файл

@ -2440,7 +2440,7 @@ int
sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
{ {
int ret = 0, slot = sisusb->font_slot, i; int ret = 0, slot = sisusb->font_slot, i;
struct font_desc *myfont; const struct font_desc *myfont;
u8 *tempbuf; u8 *tempbuf;
u16 *tempbufb; u16 *tempbufb;
size_t written; size_t written;
@ -3239,12 +3239,7 @@ static struct file_operations usb_sisusb_fops = {
}; };
static struct usb_class_driver usb_sisusb_class = { static struct usb_class_driver usb_sisusb_class = {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
.name = "usb/sisusbvga%d",
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
#else
.name = "sisusbvga%d", .name = "sisusbvga%d",
#endif
.fops = &usb_sisusb_fops, .fops = &usb_sisusb_fops,
.minor_base = SISUSB_MINOR .minor_base = SISUSB_MINOR
}; };

Просмотреть файл

@ -251,13 +251,12 @@ static struct file_operations lcd_fops = {
}; };
/* /*
* * usb class driver info in order to get a minor number from the usb core, * usb class driver info in order to get a minor number from the usb core,
* * and to have the device registered with devfs and the driver core * and to have the device registered with the driver core
* */ */
static struct usb_class_driver lcd_class = { static struct usb_class_driver lcd_class = {
.name = "usb/lcd%d", .name = "lcd%d",
.fops = &lcd_fops, .fops = &lcd_fops,
.mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.minor_base = USBLCD_MINOR, .minor_base = USBLCD_MINOR,
}; };

Просмотреть файл

@ -983,6 +983,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
reqp->number = i % NUM_SUBCASES; reqp->number = i % NUM_SUBCASES;
reqp->expected = expected; reqp->expected = expected;
u->setup_packet = (char *) &reqp->setup; u->setup_packet = (char *) &reqp->setup;
u->transfer_flags |= URB_NO_SETUP_DMA_MAP;
u->context = &context; u->context = &context;
u->complete = ctrl_complete; u->complete = ctrl_complete;
@ -1948,21 +1949,11 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
{ {
struct usbtest_dev *dev = usb_get_intfdata (intf);
down (&dev->sem);
intf->dev.power.power_state = PMSG_SUSPEND;
up (&dev->sem);
return 0; return 0;
} }
static int usbtest_resume (struct usb_interface *intf) static int usbtest_resume (struct usb_interface *intf)
{ {
struct usbtest_dev *dev = usb_get_intfdata (intf);
down (&dev->sem);
intf->dev.power.power_state = PMSG_ON;
up (&dev->sem);
return 0; return 0;
} }

Просмотреть файл

@ -11,6 +11,7 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/notifier.h>
#include "usb_mon.h" #include "usb_mon.h"
#include "../core/hcd.h" #include "../core/hcd.h"
@ -205,6 +206,23 @@ static void mon_bus_remove(struct usb_bus *ubus)
up(&mon_lock); up(&mon_lock);
} }
static int mon_notify(struct notifier_block *self, unsigned long action,
void *dev)
{
switch (action) {
case USB_BUS_ADD:
mon_bus_add(dev);
break;
case USB_BUS_REMOVE:
mon_bus_remove(dev);
}
return NOTIFY_OK;
}
static struct notifier_block mon_nb = {
.notifier_call = mon_notify,
};
/* /*
* Ops * Ops
*/ */
@ -212,8 +230,6 @@ static struct usb_mon_operations mon_ops_0 = {
.urb_submit = mon_submit, .urb_submit = mon_submit,
.urb_submit_error = mon_submit_error, .urb_submit_error = mon_submit_error,
.urb_complete = mon_complete, .urb_complete = mon_complete,
.bus_add = mon_bus_add,
.bus_remove = mon_bus_remove,
}; };
/* /*
@ -329,6 +345,8 @@ static int __init mon_init(void)
} }
// MOD_INC_USE_COUNT(which_module?); // MOD_INC_USE_COUNT(which_module?);
usb_register_notify(&mon_nb);
down(&usb_bus_list_lock); down(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) { list_for_each_entry (ubus, &usb_bus_list, bus_list) {
mon_bus_init(mondir, ubus); mon_bus_init(mondir, ubus);
@ -342,6 +360,7 @@ static void __exit mon_exit(void)
struct mon_bus *mbus; struct mon_bus *mbus;
struct list_head *p; struct list_head *p;
usb_unregister_notify(&mon_nb);
usb_mon_deregister(); usb_mon_deregister();
down(&mon_lock); down(&mon_lock);

Просмотреть файл

@ -294,7 +294,7 @@ config USB_NET_ZAURUS
This also supports some related device firmware, as used in some This also supports some related device firmware, as used in some
PDAs from Olympus and some cell phones from Motorola. PDAs from Olympus and some cell phones from Motorola.
If you install an alternate ROM image, such as the Linux 2.6 based If you install an alternate image, such as the Linux 2.6 based
versions of OpenZaurus, you should no longer need to support this versions of OpenZaurus, you should no longer need to support this
protocol. Only the "eth-fd" or "net_fd" drivers in these devices protocol. Only the "eth-fd" or "net_fd" drivers in these devices
really need this non-conformant variant of CDC Ethernet (or in really need this non-conformant variant of CDC Ethernet (or in

Просмотреть файл

@ -469,7 +469,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
0, 0,
KAWETH_CONTROL_TIMEOUT); KAWETH_CONTROL_TIMEOUT);
udelay(10000); mdelay(10);
kaweth_dbg("kaweth_reset() returns %d.",result); kaweth_dbg("kaweth_reset() returns %d.",result);

Просмотреть файл

@ -1384,7 +1384,6 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
usb_kill_urb(pegasus->rx_urb); usb_kill_urb(pegasus->rx_urb);
usb_kill_urb(pegasus->intr_urb); usb_kill_urb(pegasus->intr_urb);
} }
intf->dev.power.power_state = PMSG_SUSPEND;
return 0; return 0;
} }
@ -1392,7 +1391,6 @@ static int pegasus_resume (struct usb_interface *intf)
{ {
struct pegasus *pegasus = usb_get_intfdata(intf); struct pegasus *pegasus = usb_get_intfdata(intf);
intf->dev.power.power_state = PMSG_ON;
netif_device_attach (pegasus->net); netif_device_attach (pegasus->net);
if (netif_running(pegasus->net)) { if (netif_running(pegasus->net)) {
pegasus->rx_urb->status = 0; pegasus->rx_urb->status = 0;

Просмотреть файл

@ -181,6 +181,8 @@ PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet", PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511, VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )

Просмотреть файл

@ -909,6 +909,7 @@ static void rtl8150_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (dev) { if (dev) {
set_bit(RTL8150_UNPLUG, &dev->flags); set_bit(RTL8150_UNPLUG, &dev->flags);
tasklet_disable(&dev->tl);
unregister_netdev(dev->netdev); unregister_netdev(dev->netdev);
unlink_all_urbs(dev); unlink_all_urbs(dev);
free_all_urbs(dev); free_all_urbs(dev);

Просмотреть файл

@ -1185,7 +1185,6 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
netif_device_detach (dev->net); netif_device_detach (dev->net);
(void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->rxq);
(void) unlink_urbs (dev, &dev->txq); (void) unlink_urbs (dev, &dev->txq);
intf->dev.power.power_state = PMSG_SUSPEND;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(usbnet_suspend); EXPORT_SYMBOL_GPL(usbnet_suspend);
@ -1194,7 +1193,6 @@ int usbnet_resume (struct usb_interface *intf)
{ {
struct usbnet *dev = usb_get_intfdata(intf); struct usbnet *dev = usb_get_intfdata(intf);
intf->dev.power.power_state = PMSG_ON;
netif_device_attach (dev->net); netif_device_attach (dev->net);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
return 0; return 0;

Просмотреть файл

@ -0,0 +1,730 @@
This is the contents of some of the drivers/usb/serial/ files that had old
changelog comments. They were quite old, and out of date, and we don't keep
them anymore, so I've put them here, away from the source files, in case
people still care to see them.
- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005
-----------------------------------------------------------------------
usb-serial.h Change Log comments:
(03/26/2002) gkh
removed the port->tty check from port_paranoia_check() due to serial
consoles not having a tty device assigned to them.
(12/03/2001) gkh
removed active from the port structure.
added documentation to the usb_serial_device_type structure
(10/10/2001) gkh
added vendor and product to serial structure. Needed to determine device
owner when the device is disconnected.
(05/30/2001) gkh
added sem to port structure and removed port_lock
(10/05/2000) gkh
Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
fix bug with urb->dev not being set properly, now that the usb core
needs it.
(09/11/2000) gkh
Added usb_serial_debug_data function to help get rid of #DEBUG in the
drivers.
(08/28/2000) gkh
Added port_lock to port structure.
(08/08/2000) gkh
Added open_count to port structure.
(07/23/2000) gkh
Added bulk_out_endpointAddress to port structure.
(07/19/2000) gkh, pberger, and borchers
Modifications to allow usb-serial drivers to be modules.
-----------------------------------------------------------------------
usb-serial.c Change Log comments:
(12/10/2002) gkh
Split the ports off into their own struct device, and added a
usb-serial bus driver.
(11/19/2002) gkh
removed a few #ifdefs for the generic code and cleaned up the failure
logic in initialization.
(10/02/2002) gkh
moved the console code to console.c and out of this file.
(06/05/2002) gkh
moved location of startup() call in serial_probe() until after all
of the port information and endpoints are initialized. This makes
things easier for some drivers.
(04/10/2002) gkh
added serial_read_proc function which creates a
/proc/tty/driver/usb-serial file.
(03/27/2002) gkh
Got USB serial console code working properly and merged into the main
version of the tree. Thanks to Randy Dunlap for the initial version
of this code, and for pushing me to finish it up.
The USB serial console works with any usb serial driver device.
(03/21/2002) gkh
Moved all manipulation of port->open_count into the core. Now the
individual driver's open and close functions are called only when the
first open() and last close() is called. Making the drivers a bit
smaller and simpler.
Fixed a bug if a driver didn't have the owner field set.
(02/26/2002) gkh
Moved all locking into the main serial_* functions, instead of having
the individual drivers have to grab the port semaphore. This should
reduce races.
Reworked the MOD_INC logic a bit to always increment and decrement, even
if the generic driver is being used.
(10/10/2001) gkh
usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
help prevent child drivers from accessing the device since it is now
gone.
(09/13/2001) gkh
Moved generic driver initialize after we have registered with the USB
core. Thanks to Randy Dunlap for pointing this problem out.
(07/03/2001) gkh
Fixed module paramater size. Thanks to John Brockmeyer for the pointer.
Fixed vendor and product getting defined through the MODULE_PARM macro
if the Generic driver wasn't compiled in.
Fixed problem with generic_shutdown() not being called for drivers that
don't have a shutdown() function.
(06/06/2001) gkh
added evil hack that is needed for the prolific pl2303 device due to the
crazy way its endpoints are set up.
(05/30/2001) gkh
switched from using spinlock to a semaphore, which fixes lots of problems.
(04/08/2001) gb
Identify version on module load.
2001_02_05 gkh
Fixed buffer overflows bug with the generic serial driver. Thanks to
Todd Squires <squirest@ct0.com> for fixing this.
(01/10/2001) gkh
Fixed bug where the generic serial adaptor grabbed _any_ device that was
offered to it.
(12/12/2000) gkh
Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
moved them to the serial_open and serial_close functions.
Also fixed bug with there not being a MOD_DEC for the generic driver
(thanks to Gary Brubaker for finding this.)
(11/29/2000) gkh
Small NULL pointer initialization cleanup which saves a bit of disk image
(11/01/2000) Adam J. Richter
instead of using idVendor/idProduct pairs, usb serial drivers
now identify their hardware interest with usb_device_id tables,
which they usually have anyhow for use with MODULE_DEVICE_TABLE.
(10/05/2000) gkh
Fixed bug with urb->dev not being set properly, now that the usb
core needs it.
(09/11/2000) gkh
Removed DEBUG #ifdefs with call to usb_serial_debug_data
(08/28/2000) gkh
Added port_lock to port structure.
Added locks for SMP safeness to generic driver
Fixed the ability to open a generic device's port more than once.
(07/23/2000) gkh
Added bulk_out_endpointAddress to port structure.
(07/19/2000) gkh, pberger, and borchers
Modifications to allow usb-serial drivers to be modules.
(07/03/2000) gkh
Added more debugging to serial_ioctl call
(06/25/2000) gkh
Changed generic_write_bulk_callback to not call wake_up_interruptible
directly, but to have port_softint do it at a safer time.
(06/23/2000) gkh
Cleaned up debugging statements in a quest to find UHCI timeout bug.
(05/22/2000) gkh
Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
removed from the individual device source files.
(05/03/2000) gkh
Added the Digi Acceleport driver from Al Borchers and Peter Berger.
(05/02/2000) gkh
Changed devfs and tty register code to work properly now. This was based on
the ACM driver changes by Vojtech Pavlik.
(04/27/2000) Ryan VanderBijl
Put calls to *_paranoia_checks into one function.
(04/23/2000) gkh
Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
Moved when the startup code printed out the devices that are supported.
(04/19/2000) gkh
Added driver for ZyXEL omni.net lcd plus ISDN TA
Made startup info message specify which drivers were compiled in.
(04/03/2000) gkh
Changed the probe process to remove the module unload races.
Changed where the tty layer gets initialized to have devfs work nicer.
Added initial devfs support.
(03/26/2000) gkh
Split driver up into device specific pieces.
(03/19/2000) gkh
Fixed oops that could happen when device was removed while a program
was talking to the device.
Removed the static urbs and now all urbs are created and destroyed
dynamically.
Reworked the internal interface. Now everything is based on the
usb_serial_port structure instead of the larger usb_serial structure.
This fixes the bug that a multiport device could not have more than
one port open at one time.
(03/17/2000) gkh
Added config option for debugging messages.
Added patch for keyspan pda from Brian Warner.
(03/06/2000) gkh
Added the keyspan pda code from Brian Warner <warner@lothar.com>
Moved a bunch of the port specific stuff into its own structure. This
is in anticipation of the true multiport devices (there's a bug if you
try to access more than one port of any multiport device right now)
(02/21/2000) gkh
Made it so that any serial devices only have to specify which functions
they want to overload from the generic function calls (great,
inheritance in C, in a driver, just what I wanted...)
Added support for set_termios and ioctl function calls. No drivers take
advantage of this yet.
Removed the #ifdef MODULE, now there is no module specific code.
Cleaned up a few comments in usb-serial.h that were wrong (thanks again
to Miles Lott).
Small fix to get_free_serial.
(02/14/2000) gkh
Removed the Belkin and Peracom functionality from the driver due to
the lack of support from the vendor, and me not wanting people to
accidenatly buy the device, expecting it to work with Linux.
Added read_bulk_callback and write_bulk_callback to the type structure
for the needs of the FTDI and WhiteHEAT driver.
Changed all reverences to FTDI to FTDI_SIO at the request of Bill
Ryder.
Changed the output urb size back to the max endpoint size to make
the ftdi_sio driver have it easier, and due to the fact that it didn't
really increase the speed any.
(02/11/2000) gkh
Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
patch from Miles Lott (milos@insync.net).
Fixed bug with not restoring the minor range that a device grabs, if
the startup function fails (thanks Miles for finding this).
(02/05/2000) gkh
Added initial framework for the Keyspan PDA serial converter so that
Brian Warner has a place to put his code.
Made the ezusb specific functions generic enough that different
devices can use them (whiteheat and keyspan_pda both need them).
Split out a whole bunch of structure and other stuff to a separate
usb-serial.h file.
Made the Visor connection messages a little more understandable, now
that Miles Lott (milos@insync.net) has gotten the Generic channel to
work. Also made them always show up in the log file.
(01/25/2000) gkh
Added initial framework for FTDI serial converter so that Bill Ryder
has a place to put his code.
Added the vendor specific info from Handspring. Now we can print out
informational debug messages as well as understand what is happening.
(01/23/2000) gkh
Fixed problem of crash when trying to open a port that didn't have a
device assigned to it. Made the minor node finding a little smarter,
now it looks to find a continuous space for the new device.
(01/21/2000) gkh
Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
Fixed get_serial_by_minor which was all messed up for multi port
devices. Fixed multi port problem for generic devices. Now the number
of ports is determined by the number of bulk out endpoints for the
generic device.
(01/19/2000) gkh
Removed lots of cruft that was around from the old (pre urb) driver
interface.
Made the serial_table dynamic. This should save lots of memory when
the number of minor nodes goes up to 256.
Added initial support for devices that have more than one port.
Added more debugging comments for the Visor, and added a needed
set_configuration call.
(01/17/2000) gkh
Fixed the WhiteHEAT firmware (my processing tool had a bug)
and added new debug loader firmware for it.
Removed the put_char function as it isn't really needed.
Added visor startup commands as found by the Win98 dump.
(01/13/2000) gkh
Fixed the vendor id for the generic driver to the one I meant it to be.
(01/12/2000) gkh
Forget the version numbering...that's pretty useless...
Made the driver able to be compiled so that the user can select which
converter they want to use. This allows people who only want the Visor
support to not pay the memory size price of the WhiteHEAT.
Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
grabbed the root hub. Not good.
version 0.4.0 (01/10/2000) gkh
Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
device. Added startup function to allow firmware to be downloaded to
a device if it needs to be.
Added firmware download logic to the WhiteHEAT device.
Started to add #defines to split up the different drivers for potential
configuration option.
version 0.3.1 (12/30/99) gkh
Fixed problems with urb for bulk out.
Added initial support for multiple sets of endpoints. This enables
the Handspring Visor to be attached successfully. Only the first
bulk in / bulk out endpoint pair is being used right now.
version 0.3.0 (12/27/99) gkh
Added initial support for the Handspring Visor based on a patch from
Miles Lott (milos@sneety.insync.net)
Cleaned up the code a bunch and converted over to using urbs only.
version 0.2.3 (12/21/99) gkh
Added initial support for the Connect Tech WhiteHEAT converter.
Incremented the number of ports in expectation of getting the
WhiteHEAT to work properly (4 ports per connection).
Added notification on insertion and removal of what port the
device is/was connected to (and what kind of device it was).
version 0.2.2 (12/16/99) gkh
Changed major number to the new allocated number. We're legal now!
version 0.2.1 (12/14/99) gkh
Fixed bug that happens when device node is opened when there isn't a
device attached to it. Thanks to marek@webdesign.no for noticing this.
version 0.2.0 (11/10/99) gkh
Split up internals to make it easier to add different types of serial
converters to the code.
Added a "generic" driver that gets it's vendor and product id
from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
for the idea and sample code (from the usb scanner driver.)
Cleared up any licensing questions by releasing it under the GNU GPL.
version 0.1.2 (10/25/99) gkh
Fixed bug in detecting device.
version 0.1.1 (10/05/99) gkh
Changed the major number to not conflict with anything else.
version 0.1 (09/28/99) gkh
Can recognize the two different devices and start up a read from
device when asked to. Writes also work. No control signals yet, this
all is vendor specific data (i.e. no spec), also no control for
different baud rates or other bit settings.
Currently we are using the same devid as the acm driver. This needs
to change.
-----------------------------------------------------------------------
visor.c Change Log comments:
(06/03/2003) Judd Montgomery <judd at jpilot.org>
Added support for module parameter options for untested/unknown
devices.
(03/09/2003) gkh
Added support for the Sony Clie NZ90V device. Thanks to Martin Brachtl
<brachtl@redgrep.cz> for the information.
(03/05/2003) gkh
Think Treo support is now working.
(04/03/2002) gkh
Added support for the Sony OS 4.1 devices. Thanks to Hiroyuki ARAKI
<hiro@zob.ne.jp> for the information.
(03/27/2002) gkh
Removed assumptions that port->tty was always valid (is not true
for usb serial console devices.)
(03/23/2002) gkh
Added support for the Palm i705 device, thanks to Thomas Riemer
<tom@netmech.com> for the information.
(03/21/2002) gkh
Added support for the Palm m130 device, thanks to Udo Eisenbarth
<udo.eisenbarth@web.de> for the information.
(02/27/2002) gkh
Reworked the urb handling logic. We have no more pool, but dynamically
allocate the urb and the transfer buffer on the fly. In testing this
does not incure any measurable overhead. This also relies on the fact
that we have proper reference counting logic for urbs.
(02/21/2002) SilaS
Added initial support for the Palm m515 devices.
(02/14/2002) gkh
Added support for the Clie S-360 device.
(12/18/2001) gkh
Added better Clie support for 3.5 devices. Thanks to Geoffrey Levand
for the patch.
(11/11/2001) gkh
Added support for the m125 devices, and added check to prevent oopses
for Clié devices that lie about the number of ports they have.
(08/30/2001) gkh
Added support for the Clie devices, both the 3.5 and 4.0 os versions.
Many thanks to Daniel Burke, and Bryan Payne for helping with this.
(08/23/2001) gkh
fixed a few potential bugs pointed out by Oliver Neukum.
(05/30/2001) gkh
switched from using spinlock to a semaphore, which fixes lots of problems.
(05/28/2000) gkh
Added initial support for the Palm m500 and Palm m505 devices.
(04/08/2001) gb
Identify version on module load.
(01/21/2000) gkh
Added write_room and chars_in_buffer, as they were previously using the
generic driver versions which is all wrong now that we are using an urb
pool. Thanks to Wolfgang Grandegger for pointing this out to me.
Removed count assignment in the write function, which was not needed anymore
either. Thanks to Al Borchers for pointing this out.
(12/12/2000) gkh
Moved MOD_DEC to end of visor_close to be nicer, as the final write
message can sleep.
(11/12/2000) gkh
Fixed bug with data being dropped on the floor by forcing tty->low_latency
to be on. Hopefully this fixes the OHCI issue!
(11/01/2000) Adam J. Richter
usb_device_id table support
(10/05/2000) gkh
Fixed bug with urb->dev not being set properly, now that the usb
core needs it.
(09/11/2000) gkh
Got rid of always calling kmalloc for every urb we wrote out to the
device.
Added visor_read_callback so we can keep track of bytes in and out for
those people who like to know the speed of their device.
Removed DEBUG #ifdefs with call to usb_serial_debug_data
(09/06/2000) gkh
Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_
the host controller drivers set urb->dev = NULL when the urb is finished.
(08/28/2000) gkh
Added locks for SMP safeness.
(08/08/2000) gkh
Fixed endian problem in visor_startup.
Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
than once.
(07/23/2000) gkh
Added pool of write urbs to speed up transfers to the visor.
(07/19/2000) gkh
Added module_init and module_exit functions to handle the fact that this
driver is a loadable module now.
(07/03/2000) gkh
Added visor_set_ioctl and visor_set_termios functions (they don't do much
of anything, but are good for debugging.)
(06/25/2000) gkh
Fixed bug in visor_unthrottle that should help with the disconnect in PPP
bug that people have been reporting.
(06/23/2000) gkh
Cleaned up debugging statements in a quest to find UHCI timeout bug.
(04/27/2000) Ryan VanderBijl
Fixed memory leak in visor_close
(03/26/2000) gkh
Split driver up into device specific pieces.
-----------------------------------------------------------------------
pl2303.c Change Log comments:
2002_Mar_26 gkh
allowed driver to work properly if there is no tty assigned to a port
(this happens for serial console devices.)
2001_Oct_06 gkh
Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it.
2001_Sep_19 gkh
Added break support.
2001_Aug_30 gkh
fixed oops in write_bulk_callback.
2001_Aug_28 gkh
reworked buffer logic to be like other usb-serial drivers. Hopefully
removing some reported problems.
2001_Jun_06 gkh
finished porting to 2.4 format.
-----------------------------------------------------------------------
io_edgeport.c Change Log comments:
2003_04_03 al borchers
- fixed a bug (that shows up with dosemu) where the tty struct is
used in a callback after it has been freed
2.3 2002_03_08 greg kroah-hartman
- fixed bug when multiple devices were attached at the same time.
2.2 2001_11_14 greg kroah-hartman
- fixed bug in edge_close that kept the port from being used more
than once.
- fixed memory leak on device removal.
- fixed potential double free of memory when command urb submitting
failed.
- other small cleanups when the device is removed
2.1 2001_07_09 greg kroah-hartman
- added support for TIOCMBIS and TIOCMBIC.
(04/08/2001) gb
- Identify version on module load.
2.0 2001_03_05 greg kroah-hartman
- reworked entire driver to fit properly in with the other usb-serial
drivers. Occasional oopses still happen, but it's a good start.
1.2.3 (02/23/2001) greg kroah-hartman
- changed device table to work properly for 2.4.x final format.
- fixed problem with dropping data at high data rates.
1.2.2 (11/27/2000) greg kroah-hartman
- cleaned up more NTisms.
- Added device table for 2.4.0-test11
1.2.1 (11/08/2000) greg kroah-hartman
- Started to clean up NTisms.
- Fixed problem with dev field of urb for kernels >= 2.4.0-test9
1.2 (10/17/2000) David Iacovelli
Remove all EPIC code and GPL source
Fix RELEVANT_IFLAG macro to include flow control
changes port configuration changes.
Fix redefinition of SERIAL_MAGIC
Change all timeout values to 5 seconds
Tried to fix the UHCI multiple urb submission, but failed miserably.
it seems to work fine with OHCI.
( Greg take a look at the #if 0 at end of WriteCmdUsb() we must
find a way to work arount this UHCI bug )
1.1 (10/11/2000) David Iacovelli
Fix XON/XOFF flow control to support both IXON and IXOFF
0.9.27 (06/30/2000) David Iacovelli
Added transmit queue and now allocate urb for command writes.
0.9.26 (06/29/2000) David Iacovelli
Add support for 80251 based edgeport
0.9.25 (06/27/2000) David Iacovelli
Do not close the port if it has multiple opens.
0.9.24 (05/26/2000) David Iacovelli
Add IOCTLs to support RXTX and JAVA POS
and first cut at running BlackBox Demo
0.9.23 (05/24/2000) David Iacovelli
Add IOCTLs to support RXTX and JAVA POS
0.9.22 (05/23/2000) David Iacovelli
fixed bug in enumeration. If epconfig turns on mapping by
path after a device is already plugged in, we now update
the mapping correctly
0.9.21 (05/16/2000) David Iacovelli
Added BlockUntilChaseResp() to also wait for txcredits
Updated the way we allocate and handle write URBs
Add debug code to dump buffers
0.9.20 (05/01/2000) David Iacovelli
change driver to use usb/tts/
0.9.19 (05/01/2000) David Iacovelli
Update code to compile if DEBUG is off
0.9.18 (04/28/2000) David Iacovelli
cleanup and test tty_register with devfs
0.9.17 (04/27/2000) greg kroah-hartman
changed tty_register around to be like the way it
was before, but now it works properly with devfs.
0.9.16 (04/26/2000) david iacovelli
Fixed bug in GetProductInfo()
0.9.15 (04/25/2000) david iacovelli
Updated enumeration
0.9.14 (04/24/2000) david iacovelli
Removed all config/status IOCTLS and
converted to using /proc/edgeport
still playing with devfs
0.9.13 (04/24/2000) david iacovelli
Removed configuration based on ttyUSB0
Added support for configuration using /prod/edgeport
first attempt at using devfs (not working yet!)
Added IOCTL to GetProductInfo()
Added support for custom baud rates
Add support for random port numbers
0.9.12 (04/18/2000) david iacovelli
added additional configuration IOCTLs
use ttyUSB0 for configuration
0.9.11 (04/17/2000) greg kroah-hartman
fixed module initialization race conditions.
made all urbs dynamically allocated.
made driver devfs compatible. now it only registers the tty device
when the device is actually plugged in.
0.9.10 (04/13/2000) greg kroah-hartman
added proc interface framework.
0.9.9 (04/13/2000) david iacovelli
added enumeration code and ioctls to configure the device
0.9.8 (04/12/2000) david iacovelli
Change interrupt read start when device is plugged in
and stop when device is removed
process interrupt reads when all ports are closed
(keep value of rxBytesAvail consistent with the edgeport)
set the USB_BULK_QUEUE flag so that we can shove a bunch
of urbs at once down the pipe
0.9.7 (04/10/2000) david iacovelli
start to add enumeration code.
generate serial number for epic devices
add support for kdb
0.9.6 (03/30/2000) david iacovelli
add IOCTL to get string, manufacture, and boot descriptors
0.9.5 (03/14/2000) greg kroah-hartman
more error checking added to SerialOpen to try to fix UHCI open problem
0.9.4 (03/09/2000) greg kroah-hartman
added more error checking to handle oops when data is hanging
around and tty is abruptly closed.
0.9.3 (03/09/2000) david iacovelli
Add epic support for xon/xoff chars
play with performance
0.9.2 (03/08/2000) greg kroah-hartman
changed most "info" calls to "dbg"
implemented flow control properly in the termios call
0.9.1 (03/08/2000) david iacovelli
added EPIC support
enabled bootloader update
0.9 (03/08/2000) greg kroah-hartman
Release to IO networks.
Integrated changes that David made
made getting urbs for writing SMP safe
0.8 (03/07/2000) greg kroah-hartman
Release to IO networks.
Fixed problems that were seen in code by David.
Now both Edgeport/4 and Edgeport/2 works properly.
Changed most of the functions to use port instead of serial.
0.7 (02/27/2000) greg kroah-hartman
Milestone 3 release.
Release to IO Networks
ioctl for waiting on line change implemented.
ioctl for getting statistics implemented.
multiport support working.
lsr and msr registers are now handled properly.
change break now hooked up and working.
support for all known Edgeport devices.
0.6 (02/22/2000) greg kroah-hartman
Release to IO networks.
CHASE is implemented correctly when port is closed.
SerialOpen now blocks correctly until port is fully opened.
0.5 (02/20/2000) greg kroah-hartman
Release to IO networks.
Known problems:
modem status register changes are not sent on to the user
CHASE is not implemented when the port is closed.
0.4 (02/16/2000) greg kroah-hartman
Second cut at the CeBit demo.
Doesn't leak memory on every write to the port
Still small leaks on startup.
Added support for Edgeport/2 and Edgeport/8
0.3 (02/15/2000) greg kroah-hartman
CeBit demo release.
Force the line settings to 4800, 8, 1, e for the demo.
Warning! This version leaks memory like crazy!
0.2 (01/30/2000) greg kroah-hartman
Milestone 1 release.
Device is found by USB subsystem, enumerated, fimware is downloaded
and the descriptors are printed to the debug log, config is set, and
green light starts to blink. Open port works, and data can be sent
and received at the default settings of the UART. Loopback connector
and debug log confirms this.
0.1 (01/23/2000) greg kroah-hartman
Initial release to help IO Networks try to set up their test system.
Edgeport4 is recognized, firmware is downloaded, config is set so
device blinks green light every 3 sec. Port is bound, but opening,
closing, and sending data do not work properly.

Просмотреть файл

@ -394,6 +394,15 @@ config USB_SERIAL_MCT_U232
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 mct_u232. module will be called mct_u232.
config USB_SERIAL_NOKIA_DKU2
tristate "USB Nokia DKU2 Driver"
depends on USB_SERIAL
help
Say Y here if you want to use a Nokia DKU2 device.
To compile this driver as a module, choose M here: the
module will be called nokia_dku2.
config USB_SERIAL_PL2303 config USB_SERIAL_PL2303
tristate "USB Prolific 2303 Single Port Serial Driver" tristate "USB Prolific 2303 Single Port Serial Driver"
depends on USB_SERIAL depends on USB_SERIAL

Просмотреть файл

@ -31,6 +31,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_NOKIA_DKU2) += nokia_dku2.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o

Просмотреть файл

@ -30,9 +30,11 @@ static struct usb_driver airprime_driver = {
.id_table = id_table, .id_table = id_table,
}; };
static struct usb_serial_device_type airprime_device = { static struct usb_serial_driver airprime_device = {
.owner = THIS_MODULE, .driver = {
.name = "airprime", .owner = THIS_MODULE,
.name = "airprime",
},
.id_table = id_table, .id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE, .num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE,

Просмотреть файл

@ -121,10 +121,12 @@ static struct usb_driver belkin_driver = {
}; };
/* All of the device info needed for the serial converters */ /* All of the device info needed for the serial converters */
static struct usb_serial_device_type belkin_device = { static struct usb_serial_driver belkin_device = {
.owner = THIS_MODULE, .driver = {
.name = "Belkin / Peracom / GoHubs USB Serial Adapter", .owner = THIS_MODULE,
.short_name = "belkin", .name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
.id_table = id_table_combined, .id_table = id_table_combined,
.num_interrupt_in = 1, .num_interrupt_in = 1,
.num_bulk_in = 1, .num_bulk_in = 1,

Просмотреть файл

@ -18,7 +18,7 @@
static int usb_serial_device_match (struct device *dev, struct device_driver *drv) static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{ {
struct usb_serial_device_type *driver; struct usb_serial_driver *driver;
const struct usb_serial_port *port; const struct usb_serial_port *port;
/* /*
@ -44,7 +44,7 @@ struct bus_type usb_serial_bus_type = {
static int usb_serial_device_probe (struct device *dev) static int usb_serial_device_probe (struct device *dev)
{ {
struct usb_serial_device_type *driver; struct usb_serial_driver *driver;
struct usb_serial_port *port; struct usb_serial_port *port;
int retval = 0; int retval = 0;
int minor; int minor;
@ -57,13 +57,13 @@ static int usb_serial_device_probe (struct device *dev)
driver = port->serial->type; driver = port->serial->type;
if (driver->port_probe) { if (driver->port_probe) {
if (!try_module_get(driver->owner)) { if (!try_module_get(driver->driver.owner)) {
dev_err(dev, "module get failed, exiting\n"); dev_err(dev, "module get failed, exiting\n");
retval = -EIO; retval = -EIO;
goto exit; goto exit;
} }
retval = driver->port_probe (port); retval = driver->port_probe (port);
module_put(driver->owner); module_put(driver->driver.owner);
if (retval) if (retval)
goto exit; goto exit;
} }
@ -72,7 +72,7 @@ static int usb_serial_device_probe (struct device *dev)
tty_register_device (usb_serial_tty_driver, minor, dev); tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev, dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d\n", "%s converter now attached to ttyUSB%d\n",
driver->name, minor); driver->description, minor);
exit: exit:
return retval; return retval;
@ -80,7 +80,7 @@ exit:
static int usb_serial_device_remove (struct device *dev) static int usb_serial_device_remove (struct device *dev)
{ {
struct usb_serial_device_type *driver; struct usb_serial_driver *driver;
struct usb_serial_port *port; struct usb_serial_port *port;
int retval = 0; int retval = 0;
int minor; int minor;
@ -92,43 +92,38 @@ static int usb_serial_device_remove (struct device *dev)
driver = port->serial->type; driver = port->serial->type;
if (driver->port_remove) { if (driver->port_remove) {
if (!try_module_get(driver->owner)) { if (!try_module_get(driver->driver.owner)) {
dev_err(dev, "module get failed, exiting\n"); dev_err(dev, "module get failed, exiting\n");
retval = -EIO; retval = -EIO;
goto exit; goto exit;
} }
retval = driver->port_remove (port); retval = driver->port_remove (port);
module_put(driver->owner); module_put(driver->driver.owner);
} }
exit: exit:
minor = port->number; minor = port->number;
tty_unregister_device (usb_serial_tty_driver, minor); tty_unregister_device (usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->name, minor); driver->description, minor);
return retval; return retval;
} }
int usb_serial_bus_register(struct usb_serial_device_type *device) int usb_serial_bus_register(struct usb_serial_driver *driver)
{ {
int retval; int retval;
if (device->short_name) driver->driver.bus = &usb_serial_bus_type;
device->driver.name = (char *)device->short_name; driver->driver.probe = usb_serial_device_probe;
else driver->driver.remove = usb_serial_device_remove;
device->driver.name = (char *)device->name;
device->driver.bus = &usb_serial_bus_type;
device->driver.probe = usb_serial_device_probe;
device->driver.remove = usb_serial_device_remove;
device->driver.owner = device->owner;
retval = driver_register(&device->driver); retval = driver_register(&driver->driver);
return retval; return retval;
} }
void usb_serial_bus_deregister(struct usb_serial_device_type *device) void usb_serial_bus_deregister(struct usb_serial_driver *driver)
{ {
driver_unregister (&device->driver); driver_unregister(&driver->driver);
} }

Просмотреть файл

@ -67,15 +67,17 @@ MODULE_DEVICE_TABLE (usb, id_table);
static struct usb_driver cp2101_driver = { static struct usb_driver cp2101_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "CP2101", .name = "cp2101",
.probe = usb_serial_probe, .probe = usb_serial_probe,
.disconnect = usb_serial_disconnect, .disconnect = usb_serial_disconnect,
.id_table = id_table, .id_table = id_table,
}; };
static struct usb_serial_device_type cp2101_device = { static struct usb_serial_driver cp2101_device = {
.owner = THIS_MODULE, .driver = {
.name = "CP2101", .owner = THIS_MODULE,
.name = "cp2101",
},
.id_table = id_table, .id_table = id_table,
.num_interrupt_in = 0, .num_interrupt_in = 0,
.num_bulk_in = 0, .num_bulk_in = 0,

Просмотреть файл

@ -83,10 +83,12 @@ static struct usb_driver cyberjack_driver = {
.id_table = id_table, .id_table = id_table,
}; };
static struct usb_serial_device_type cyberjack_device = { static struct usb_serial_driver cyberjack_device = {
.owner = THIS_MODULE, .driver = {
.name = "Reiner SCT Cyberjack USB card reader", .owner = THIS_MODULE,
.short_name = "cyberjack", .name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table, .id_table = id_table,
.num_interrupt_in = 1, .num_interrupt_in = 1,
.num_bulk_in = 1, .num_bulk_in = 1,

Просмотреть файл

@ -176,10 +176,12 @@ static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, u
static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count); static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count);
static struct usb_serial_device_type cypress_earthmate_device = { static struct usb_serial_driver cypress_earthmate_device = {
.owner = THIS_MODULE, .driver = {
.name = "DeLorme Earthmate USB", .owner = THIS_MODULE,
.short_name = "earthmate", .name = "earthmate",
},
.description = "DeLorme Earthmate USB",
.id_table = id_table_earthmate, .id_table = id_table_earthmate,
.num_interrupt_in = 1, .num_interrupt_in = 1,
.num_interrupt_out = 1, .num_interrupt_out = 1,
@ -203,10 +205,12 @@ static struct usb_serial_device_type cypress_earthmate_device = {
.write_int_callback = cypress_write_int_callback, .write_int_callback = cypress_write_int_callback,
}; };
static struct usb_serial_device_type cypress_hidcom_device = { static struct usb_serial_driver cypress_hidcom_device = {
.owner = THIS_MODULE, .driver = {
.name = "HID->COM RS232 Adapter", .owner = THIS_MODULE,
.short_name = "cyphidcom", .name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
.id_table = id_table_cyphidcomrs232, .id_table = id_table_cyphidcomrs232,
.num_interrupt_in = 1, .num_interrupt_in = 1,
.num_interrupt_out = 1, .num_interrupt_out = 1,

Просмотреть файл

@ -503,10 +503,12 @@ static struct usb_driver digi_driver = {
/* device info needed for the Digi serial converter */ /* device info needed for the Digi serial converter */
static struct usb_serial_device_type digi_acceleport_2_device = { static struct usb_serial_driver digi_acceleport_2_device = {
.owner = THIS_MODULE, .driver = {
.name = "Digi 2 port USB adapter", .owner = THIS_MODULE,
.short_name = "digi_2", .name = "digi_2",
},
.description = "Digi 2 port USB adapter",
.id_table = id_table_2, .id_table = id_table_2,
.num_interrupt_in = 0, .num_interrupt_in = 0,
.num_bulk_in = 4, .num_bulk_in = 4,
@ -530,10 +532,12 @@ static struct usb_serial_device_type digi_acceleport_2_device = {
.shutdown = digi_shutdown, .shutdown = digi_shutdown,
}; };
static struct usb_serial_device_type digi_acceleport_4_device = { static struct usb_serial_driver digi_acceleport_4_device = {
.owner = THIS_MODULE, .driver = {
.name = "Digi 4 port USB adapter", .owner = THIS_MODULE,
.short_name = "digi_4", .name = "digi_4",
},
.description = "Digi 4 port USB adapter",
.id_table = id_table_4, .id_table = id_table_4,
.num_interrupt_in = 0, .num_interrupt_in = 0,
.num_bulk_in = 5, .num_bulk_in = 5,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше