USB fixes for 3.4-rc2
Here are a number of fixes for the USB core and drivers for 3.4-rc2 Lots of tiny xhci fixes here, a few usb-serial driver fixes and new device ids, and a smattering of other minor fixes in different USB drivers. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iEYEABECAAYFAk+HVPUACgkQMUfUDdst+ykskwCfV0ypvXzg0JMTBqNDHb8BDmcZ Ca4An0pZyzO2JsUHTfGUAvm6SFANqCnk =KB61 -----END PGP SIGNATURE----- Merge tag 'usb-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a number of fixes for the USB core and drivers for 3.4-rc2 Lots of tiny xhci fixes here, a few usb-serial driver fixes and new device ids, and a smattering of other minor fixes in different USB drivers. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'usb-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (30 commits) USB: update usbtmc api documentation xHCI: Correct the #define XHCI_LEGACY_DISABLE_SMI xHCI: use gfp flags from caller instead of GFP_ATOMIC xHCI: add XHCI_RESET_ON_RESUME quirk for VIA xHCI host USB: fix bug of device descriptor got from superspeed device xhci: Fix register save/restore order. xhci: Restore event ring dequeue pointer on resume. xhci: Don't write zeroed pointers to xHC registers. xhci: Warn when hosts don't halt. xhci: don't re-enable IE constantly usb: xhci: fix section mismatch in linux-next xHCI: correct to print the true HSEE of USBCMD USB: serial: fix race between probe and open UHCI: hub_status_data should indicate if ports are resuming EHCI: keep track of ports being resumed and indicate in hub_status_data USB: fix race between root-hub suspend and remote wakeup USB: sierra: add support for Sierra Wireless MC7710 USB: ftdi_sio: fix race condition in TIOCMIWAIT, and abort of TIOCMIWAIT when the device is removed USB: ftdi_sio: fix status line change handling for TIOCMIWAIT and TIOCGICOUNT USB: don't ignore suspend errors for root hubs ...
This commit is contained in:
commit
7c427f4550
32 changed files with 216 additions and 118 deletions
|
@ -1,5 +1,5 @@
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/interface_capabilities
|
What: /sys/bus/usb/drivers/usbtmc/*/interface_capabilities
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/device_capabilities
|
What: /sys/bus/usb/drivers/usbtmc/*/device_capabilities
|
||||||
Date: August 2008
|
Date: August 2008
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
Description:
|
Description:
|
||||||
|
@ -12,8 +12,8 @@ Description:
|
||||||
The files are read only.
|
The files are read only.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_interface_capabilities
|
What: /sys/bus/usb/drivers/usbtmc/*/usb488_interface_capabilities
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_device_capabilities
|
What: /sys/bus/usb/drivers/usbtmc/*/usb488_device_capabilities
|
||||||
Date: August 2008
|
Date: August 2008
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
Description:
|
Description:
|
||||||
|
@ -27,7 +27,7 @@ Description:
|
||||||
The files are read only.
|
The files are read only.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/TermChar
|
What: /sys/bus/usb/drivers/usbtmc/*/TermChar
|
||||||
Date: August 2008
|
Date: August 2008
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
Description:
|
Description:
|
||||||
|
@ -40,7 +40,7 @@ Description:
|
||||||
sent to the device or not.
|
sent to the device or not.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/TermCharEnabled
|
What: /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
|
||||||
Date: August 2008
|
Date: August 2008
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
Description:
|
Description:
|
||||||
|
@ -51,7 +51,7 @@ Description:
|
||||||
published by the USB-IF.
|
published by the USB-IF.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/devices/*/auto_abort
|
What: /sys/bus/usb/drivers/usbtmc/*/auto_abort
|
||||||
Date: August 2008
|
Date: August 2008
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
Description:
|
Description:
|
||||||
|
|
|
@ -168,6 +168,28 @@ that if the completion handler or anyone else tries to resubmit it
|
||||||
they will get a -EPERM error. Thus you can be sure that when
|
they will get a -EPERM error. Thus you can be sure that when
|
||||||
usb_kill_urb() returns, the URB is totally idle.
|
usb_kill_urb() returns, the URB is totally idle.
|
||||||
|
|
||||||
|
There is a lifetime issue to consider. An URB may complete at any
|
||||||
|
time, and the completion handler may free the URB. If this happens
|
||||||
|
while usb_unlink_urb or usb_kill_urb is running, it will cause a
|
||||||
|
memory-access violation. The driver is responsible for avoiding this,
|
||||||
|
which often means some sort of lock will be needed to prevent the URB
|
||||||
|
from being deallocated while it is still in use.
|
||||||
|
|
||||||
|
On the other hand, since usb_unlink_urb may end up calling the
|
||||||
|
completion handler, the handler must not take any lock that is held
|
||||||
|
when usb_unlink_urb is invoked. The general solution to this problem
|
||||||
|
is to increment the URB's reference count while holding the lock, then
|
||||||
|
drop the lock and call usb_unlink_urb or usb_kill_urb, and then
|
||||||
|
decrement the URB's reference count. You increment the reference
|
||||||
|
count by calling
|
||||||
|
|
||||||
|
struct urb *usb_get_urb(struct urb *urb)
|
||||||
|
|
||||||
|
(ignore the return value; it is the same as the argument) and
|
||||||
|
decrement the reference count by calling usb_free_urb. Of course,
|
||||||
|
none of this is necessary if there's no danger of the URB being freed
|
||||||
|
by the completion handler.
|
||||||
|
|
||||||
|
|
||||||
1.7. What about the completion handler?
|
1.7. What about the completion handler?
|
||||||
|
|
||||||
|
|
|
@ -183,10 +183,10 @@ An input control transfer to get a port status.
|
||||||
d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
|
d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
|
||||||
d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
|
d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
|
||||||
|
|
||||||
An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
|
An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte
|
||||||
to a storage device at address 5:
|
Bulk wrapper to a storage device at address 5:
|
||||||
|
|
||||||
dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
|
dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000
|
||||||
dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
|
dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
|
||||||
|
|
||||||
* Raw binary format and API
|
* Raw binary format and API
|
||||||
|
|
|
@ -2,14 +2,6 @@
|
||||||
# USB device configuration
|
# USB device configuration
|
||||||
#
|
#
|
||||||
|
|
||||||
menuconfig USB_SUPPORT
|
|
||||||
bool "USB support"
|
|
||||||
depends on HAS_IOMEM
|
|
||||||
default y
|
|
||||||
---help---
|
|
||||||
This option adds core support for Universal Serial Bus (USB).
|
|
||||||
You will also need drivers from the following menu to make use of it.
|
|
||||||
|
|
||||||
# many non-PCI SOC chips embed OHCI
|
# many non-PCI SOC chips embed OHCI
|
||||||
config USB_ARCH_HAS_OHCI
|
config USB_ARCH_HAS_OHCI
|
||||||
boolean
|
boolean
|
||||||
|
@ -63,6 +55,14 @@ config USB_ARCH_HAS_XHCI
|
||||||
boolean
|
boolean
|
||||||
default PCI
|
default PCI
|
||||||
|
|
||||||
|
menuconfig USB_SUPPORT
|
||||||
|
bool "USB support"
|
||||||
|
depends on HAS_IOMEM
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
This option adds core support for Universal Serial Bus (USB).
|
||||||
|
You will also need drivers from the following menu to make use of it.
|
||||||
|
|
||||||
if USB_SUPPORT
|
if USB_SUPPORT
|
||||||
|
|
||||||
config USB_COMMON
|
config USB_COMMON
|
||||||
|
|
|
@ -1189,8 +1189,13 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
status = usb_suspend_device(udev, msg);
|
status = usb_suspend_device(udev, msg);
|
||||||
|
|
||||||
/* Again, ignore errors during system sleep transitions */
|
/*
|
||||||
if (!PMSG_IS_AUTO(msg))
|
* Ignore errors from non-root-hub devices during
|
||||||
|
* system sleep transitions. For the most part,
|
||||||
|
* these devices should go to low power anyway when
|
||||||
|
* the entire bus is suspended.
|
||||||
|
*/
|
||||||
|
if (udev->parent && !PMSG_IS_AUTO(msg))
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1978,6 +1978,18 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
|
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
|
||||||
hcd->state = HC_STATE_SUSPENDED;
|
hcd->state = HC_STATE_SUSPENDED;
|
||||||
|
|
||||||
|
/* Did we race with a root-hub wakeup event? */
|
||||||
|
if (rhdev->do_remote_wakeup) {
|
||||||
|
char buffer[6];
|
||||||
|
|
||||||
|
status = hcd->driver->hub_status_data(hcd, buffer);
|
||||||
|
if (status != 0) {
|
||||||
|
dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n");
|
||||||
|
hcd_bus_resume(rhdev, PMSG_AUTO_RESUME);
|
||||||
|
status = -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
spin_lock_irq(&hcd_root_hub_lock);
|
spin_lock_irq(&hcd_root_hub_lock);
|
||||||
if (!HCD_DEAD(hcd)) {
|
if (!HCD_DEAD(hcd)) {
|
||||||
|
|
|
@ -3163,6 +3163,22 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
||||||
if (retval)
|
if (retval)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some superspeed devices have finished the link training process
|
||||||
|
* and attached to a superspeed hub port, but the device descriptor
|
||||||
|
* got from those devices show they aren't superspeed devices. Warm
|
||||||
|
* reset the port attached by the devices can fix them.
|
||||||
|
*/
|
||||||
|
if ((udev->speed == USB_SPEED_SUPER) &&
|
||||||
|
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
|
||||||
|
dev_err(&udev->dev, "got a wrong device descriptor, "
|
||||||
|
"warm reset device\n");
|
||||||
|
hub_port_reset(hub, port1, udev,
|
||||||
|
HUB_BH_RESET_TIME, true);
|
||||||
|
retval = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
|
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
|
||||||
udev->speed == USB_SPEED_SUPER)
|
udev->speed == USB_SPEED_SUPER)
|
||||||
i = 512;
|
i = 512;
|
||||||
|
|
|
@ -308,7 +308,8 @@ static void sg_complete(struct urb *urb)
|
||||||
retval = usb_unlink_urb(io->urbs [i]);
|
retval = usb_unlink_urb(io->urbs [i]);
|
||||||
if (retval != -EINPROGRESS &&
|
if (retval != -EINPROGRESS &&
|
||||||
retval != -ENODEV &&
|
retval != -ENODEV &&
|
||||||
retval != -EBUSY)
|
retval != -EBUSY &&
|
||||||
|
retval != -EIDRM)
|
||||||
dev_err(&io->dev->dev,
|
dev_err(&io->dev->dev,
|
||||||
"%s, unlink --> %d\n",
|
"%s, unlink --> %d\n",
|
||||||
__func__, retval);
|
__func__, retval);
|
||||||
|
@ -317,7 +318,6 @@ static void sg_complete(struct urb *urb)
|
||||||
}
|
}
|
||||||
spin_lock(&io->lock);
|
spin_lock(&io->lock);
|
||||||
}
|
}
|
||||||
urb->dev = NULL;
|
|
||||||
|
|
||||||
/* on the last completion, signal usb_sg_wait() */
|
/* on the last completion, signal usb_sg_wait() */
|
||||||
io->bytes += urb->actual_length;
|
io->bytes += urb->actual_length;
|
||||||
|
@ -524,7 +524,6 @@ void usb_sg_wait(struct usb_sg_request *io)
|
||||||
case -ENXIO: /* hc didn't queue this one */
|
case -ENXIO: /* hc didn't queue this one */
|
||||||
case -EAGAIN:
|
case -EAGAIN:
|
||||||
case -ENOMEM:
|
case -ENOMEM:
|
||||||
io->urbs[i]->dev = NULL;
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
yield();
|
yield();
|
||||||
break;
|
break;
|
||||||
|
@ -542,7 +541,6 @@ void usb_sg_wait(struct usb_sg_request *io)
|
||||||
|
|
||||||
/* fail any uncompleted urbs */
|
/* fail any uncompleted urbs */
|
||||||
default:
|
default:
|
||||||
io->urbs[i]->dev = NULL;
|
|
||||||
io->urbs[i]->status = retval;
|
io->urbs[i]->status = retval;
|
||||||
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
|
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
|
||||||
__func__, retval);
|
__func__, retval);
|
||||||
|
@ -593,7 +591,10 @@ void usb_sg_cancel(struct usb_sg_request *io)
|
||||||
if (!io->urbs [i]->dev)
|
if (!io->urbs [i]->dev)
|
||||||
continue;
|
continue;
|
||||||
retval = usb_unlink_urb(io->urbs [i]);
|
retval = usb_unlink_urb(io->urbs [i]);
|
||||||
if (retval != -EINPROGRESS && retval != -EBUSY)
|
if (retval != -EINPROGRESS
|
||||||
|
&& retval != -ENODEV
|
||||||
|
&& retval != -EBUSY
|
||||||
|
&& retval != -EIDRM)
|
||||||
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
|
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
|
||||||
__func__, retval);
|
__func__, retval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,6 +539,10 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
|
||||||
* never submitted, or it was unlinked before, or the hardware is already
|
* never submitted, or it was unlinked before, or the hardware is already
|
||||||
* finished with it), even if the completion handler has not yet run.
|
* finished with it), even if the completion handler has not yet run.
|
||||||
*
|
*
|
||||||
|
* The URB must not be deallocated while this routine is running. In
|
||||||
|
* particular, when a driver calls this routine, it must insure that the
|
||||||
|
* completion handler cannot deallocate the URB.
|
||||||
|
*
|
||||||
* Unlinking and Endpoint Queues:
|
* Unlinking and Endpoint Queues:
|
||||||
*
|
*
|
||||||
* [The behaviors and guarantees described below do not apply to virtual
|
* [The behaviors and guarantees described below do not apply to virtual
|
||||||
|
@ -603,6 +607,10 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb);
|
||||||
* with error -EPERM. Thus even if the URB's completion handler always
|
* with error -EPERM. Thus even if the URB's completion handler always
|
||||||
* tries to resubmit, it will not succeed and the URB will become idle.
|
* tries to resubmit, it will not succeed and the URB will become idle.
|
||||||
*
|
*
|
||||||
|
* The URB must not be deallocated while this routine is running. In
|
||||||
|
* particular, when a driver calls this routine, it must insure that the
|
||||||
|
* completion handler cannot deallocate the URB.
|
||||||
|
*
|
||||||
* This routine may not be used in an interrupt context (such as a bottom
|
* This routine may not be used in an interrupt context (such as a bottom
|
||||||
* half or a completion handler), or when holding a spinlock, or in other
|
* half or a completion handler), or when holding a spinlock, or in other
|
||||||
* situations where the caller can't schedule().
|
* situations where the caller can't schedule().
|
||||||
|
@ -640,6 +648,10 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
|
||||||
* with error -EPERM. Thus even if the URB's completion handler always
|
* with error -EPERM. Thus even if the URB's completion handler always
|
||||||
* tries to resubmit, it will not succeed and the URB will become idle.
|
* tries to resubmit, it will not succeed and the URB will become idle.
|
||||||
*
|
*
|
||||||
|
* The URB must not be deallocated while this routine is running. In
|
||||||
|
* particular, when a driver calls this routine, it must insure that the
|
||||||
|
* completion handler cannot deallocate the URB.
|
||||||
|
*
|
||||||
* This routine may not be used in an interrupt context (such as a bottom
|
* This routine may not be used in an interrupt context (such as a bottom
|
||||||
* half or a completion handler), or when holding a spinlock, or in other
|
* half or a completion handler), or when holding a spinlock, or in other
|
||||||
* situations where the caller can't schedule().
|
* situations where the caller can't schedule().
|
||||||
|
|
|
@ -1574,7 +1574,6 @@ static void destroy_ep_files (struct dev_data *dev)
|
||||||
DBG (dev, "%s %d\n", __func__, dev->state);
|
DBG (dev, "%s %d\n", __func__, dev->state);
|
||||||
|
|
||||||
/* dev->state must prevent interference */
|
/* dev->state must prevent interference */
|
||||||
restart:
|
|
||||||
spin_lock_irq (&dev->lock);
|
spin_lock_irq (&dev->lock);
|
||||||
while (!list_empty(&dev->epfiles)) {
|
while (!list_empty(&dev->epfiles)) {
|
||||||
struct ep_data *ep;
|
struct ep_data *ep;
|
||||||
|
|
|
@ -347,6 +347,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
|
||||||
if (ehci->debug)
|
if (ehci->debug)
|
||||||
dbgp_external_startup();
|
dbgp_external_startup();
|
||||||
|
|
||||||
|
ehci->port_c_suspend = ehci->suspended_ports =
|
||||||
|
ehci->resuming_ports = 0;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,6 +941,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||||
* like usb_port_resume() does.
|
* like usb_port_resume() does.
|
||||||
*/
|
*/
|
||||||
ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
|
ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
|
||||||
|
set_bit(i, &ehci->resuming_ports);
|
||||||
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
|
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
|
||||||
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
|
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,17 +223,12 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||||
* remote wakeup, we must fail the suspend.
|
* remote wakeup, we must fail the suspend.
|
||||||
*/
|
*/
|
||||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||||
port = HCS_N_PORTS(ehci->hcs_params);
|
if (ehci->resuming_ports) {
|
||||||
while (port--) {
|
|
||||||
if (ehci->reset_done[port] != 0) {
|
|
||||||
spin_unlock_irq(&ehci->lock);
|
spin_unlock_irq(&ehci->lock);
|
||||||
ehci_dbg(ehci, "suspend failed because "
|
ehci_dbg(ehci, "suspend failed because a port is resuming\n");
|
||||||
"port %d is resuming\n",
|
|
||||||
port + 1);
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* stop schedules, clean any completed work */
|
/* stop schedules, clean any completed work */
|
||||||
if (ehci->rh_state == EHCI_RH_RUNNING)
|
if (ehci->rh_state == EHCI_RH_RUNNING)
|
||||||
|
@ -554,16 +549,12 @@ static int
|
||||||
ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||||
u32 temp, status = 0;
|
u32 temp, status;
|
||||||
u32 mask;
|
u32 mask;
|
||||||
int ports, i, retval = 1;
|
int ports, i, retval = 1;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 ppcd = 0;
|
u32 ppcd = 0;
|
||||||
|
|
||||||
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
|
|
||||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* init status to no-changes */
|
/* init status to no-changes */
|
||||||
buf [0] = 0;
|
buf [0] = 0;
|
||||||
ports = HCS_N_PORTS (ehci->hcs_params);
|
ports = HCS_N_PORTS (ehci->hcs_params);
|
||||||
|
@ -572,6 +563,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
||||||
retval++;
|
retval++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inform the core about resumes-in-progress by returning
|
||||||
|
* a non-zero value even if there are no status changes.
|
||||||
|
*/
|
||||||
|
status = ehci->resuming_ports;
|
||||||
|
|
||||||
/* Some boards (mostly VIA?) report bogus overcurrent indications,
|
/* Some boards (mostly VIA?) report bogus overcurrent indications,
|
||||||
* causing massive log spam unless we completely ignore them. It
|
* causing massive log spam unless we completely ignore them. It
|
||||||
* may be relevant that VIA VT8235 controllers, where PORT_POWER is
|
* may be relevant that VIA VT8235 controllers, where PORT_POWER is
|
||||||
|
@ -846,6 +842,7 @@ static int ehci_hub_control (
|
||||||
ehci_writel(ehci,
|
ehci_writel(ehci,
|
||||||
temp & ~(PORT_RWC_BITS | PORT_RESUME),
|
temp & ~(PORT_RWC_BITS | PORT_RESUME),
|
||||||
status_reg);
|
status_reg);
|
||||||
|
clear_bit(wIndex, &ehci->resuming_ports);
|
||||||
retval = handshake(ehci, status_reg,
|
retval = handshake(ehci, status_reg,
|
||||||
PORT_RESUME, 0, 2000 /* 2msec */);
|
PORT_RESUME, 0, 2000 /* 2msec */);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
|
@ -864,6 +861,7 @@ static int ehci_hub_control (
|
||||||
ehci->reset_done[wIndex])) {
|
ehci->reset_done[wIndex])) {
|
||||||
status |= USB_PORT_STAT_C_RESET << 16;
|
status |= USB_PORT_STAT_C_RESET << 16;
|
||||||
ehci->reset_done [wIndex] = 0;
|
ehci->reset_done [wIndex] = 0;
|
||||||
|
clear_bit(wIndex, &ehci->resuming_ports);
|
||||||
|
|
||||||
/* force reset to complete */
|
/* force reset to complete */
|
||||||
ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
|
ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
|
||||||
|
@ -884,8 +882,10 @@ static int ehci_hub_control (
|
||||||
ehci_readl(ehci, status_reg));
|
ehci_readl(ehci, status_reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(temp & (PORT_RESUME|PORT_RESET)))
|
if (!(temp & (PORT_RESUME|PORT_RESET))) {
|
||||||
ehci->reset_done[wIndex] = 0;
|
ehci->reset_done[wIndex] = 0;
|
||||||
|
clear_bit(wIndex, &ehci->resuming_ports);
|
||||||
|
}
|
||||||
|
|
||||||
/* transfer dedicated ports to the companion hc */
|
/* transfer dedicated ports to the companion hc */
|
||||||
if ((temp & PORT_CONNECT) &&
|
if ((temp & PORT_CONNECT) &&
|
||||||
|
@ -920,6 +920,7 @@ static int ehci_hub_control (
|
||||||
status |= USB_PORT_STAT_SUSPEND;
|
status |= USB_PORT_STAT_SUSPEND;
|
||||||
} else if (test_bit(wIndex, &ehci->suspended_ports)) {
|
} else if (test_bit(wIndex, &ehci->suspended_ports)) {
|
||||||
clear_bit(wIndex, &ehci->suspended_ports);
|
clear_bit(wIndex, &ehci->suspended_ports);
|
||||||
|
clear_bit(wIndex, &ehci->resuming_ports);
|
||||||
ehci->reset_done[wIndex] = 0;
|
ehci->reset_done[wIndex] = 0;
|
||||||
if (temp & PORT_PE)
|
if (temp & PORT_PE)
|
||||||
set_bit(wIndex, &ehci->port_c_suspend);
|
set_bit(wIndex, &ehci->port_c_suspend);
|
||||||
|
|
|
@ -224,6 +224,7 @@ static int tegra_ehci_hub_control(
|
||||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||||
/* start resume signalling */
|
/* start resume signalling */
|
||||||
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
|
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
|
||||||
|
set_bit(wIndex-1, &ehci->resuming_ports);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||||
msleep(20);
|
msleep(20);
|
||||||
|
@ -236,6 +237,7 @@ static int tegra_ehci_hub_control(
|
||||||
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
|
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
|
||||||
|
|
||||||
ehci->reset_done[wIndex-1] = 0;
|
ehci->reset_done[wIndex-1] = 0;
|
||||||
|
clear_bit(wIndex-1, &ehci->resuming_ports);
|
||||||
|
|
||||||
tegra->port_resuming = 1;
|
tegra->port_resuming = 1;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -117,6 +117,8 @@ struct ehci_hcd { /* one per controller */
|
||||||
the change-suspend feature turned on */
|
the change-suspend feature turned on */
|
||||||
unsigned long suspended_ports; /* which ports are
|
unsigned long suspended_ports; /* which ports are
|
||||||
suspended */
|
suspended */
|
||||||
|
unsigned long resuming_ports; /* which ports have
|
||||||
|
started to resume */
|
||||||
|
|
||||||
/* per-HC memory pools (could be per-bus, but ...) */
|
/* per-HC memory pools (could be per-bus, but ...) */
|
||||||
struct dma_pool *qh_pool; /* qh per active urb */
|
struct dma_pool *qh_pool; /* qh per active urb */
|
||||||
|
|
|
@ -825,9 +825,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable any BIOS SMIs */
|
val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||||
writel(XHCI_LEGACY_DISABLE_SMI,
|
/* Mask off (turn off) any enabled SMIs */
|
||||||
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
val &= XHCI_LEGACY_DISABLE_SMI;
|
||||||
|
/* Mask all SMI events bits, RW1C */
|
||||||
|
val |= XHCI_LEGACY_SMI_EVENTS;
|
||||||
|
/* Disable any BIOS SMIs and clear all SMI events*/
|
||||||
|
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
|
||||||
|
|
||||||
if (usb_is_intel_switchable_xhci(pdev))
|
if (usb_is_intel_switchable_xhci(pdev))
|
||||||
usb_enable_xhci_ports(pdev);
|
usb_enable_xhci_ports(pdev);
|
||||||
|
|
|
@ -196,11 +196,12 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
||||||
status = get_hub_status_data(uhci, buf);
|
status = get_hub_status_data(uhci, buf);
|
||||||
|
|
||||||
switch (uhci->rh_state) {
|
switch (uhci->rh_state) {
|
||||||
case UHCI_RH_SUSPENDING:
|
|
||||||
case UHCI_RH_SUSPENDED:
|
case UHCI_RH_SUSPENDED:
|
||||||
/* if port change, ask to be resumed */
|
/* if port change, ask to be resumed */
|
||||||
if (status || uhci->resuming_ports)
|
if (status || uhci->resuming_ports) {
|
||||||
|
status = 1;
|
||||||
usb_hcd_resume_root_hub(hcd);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UHCI_RH_AUTO_STOPPED:
|
case UHCI_RH_AUTO_STOPPED:
|
||||||
|
|
|
@ -119,7 +119,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci)
|
||||||
xhci_dbg(xhci, " Event Interrupts %s\n",
|
xhci_dbg(xhci, " Event Interrupts %s\n",
|
||||||
(temp & CMD_EIE) ? "enabled " : "disabled");
|
(temp & CMD_EIE) ? "enabled " : "disabled");
|
||||||
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
|
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
|
||||||
(temp & CMD_EIE) ? "enabled " : "disabled");
|
(temp & CMD_HSEIE) ? "enabled " : "disabled");
|
||||||
xhci_dbg(xhci, " HC has %sfinished light reset\n",
|
xhci_dbg(xhci, " HC has %sfinished light reset\n",
|
||||||
(temp & CMD_LRESET) ? "not " : "");
|
(temp & CMD_LRESET) ? "not " : "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,9 @@
|
||||||
/* USB Legacy Support Control and Status Register - section 7.1.2 */
|
/* USB Legacy Support Control and Status Register - section 7.1.2 */
|
||||||
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
|
||||||
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
|
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
|
||||||
/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
|
||||||
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
|
#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17))
|
||||||
|
#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29)
|
||||||
|
|
||||||
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
|
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
|
||||||
#define XHCI_L1C (1 << 16)
|
#define XHCI_L1C (1 << 16)
|
||||||
|
|
|
@ -1796,11 +1796,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Free the Event Ring Segment Table and the actual Event Ring */
|
/* Free the Event Ring Segment Table and the actual Event Ring */
|
||||||
if (xhci->ir_set) {
|
|
||||||
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
|
|
||||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
|
|
||||||
xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
|
|
||||||
}
|
|
||||||
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
|
||||||
if (xhci->erst.entries)
|
if (xhci->erst.entries)
|
||||||
dma_free_coherent(&pdev->dev, size,
|
dma_free_coherent(&pdev->dev, size,
|
||||||
|
@ -1812,7 +1807,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
xhci->event_ring = NULL;
|
xhci->event_ring = NULL;
|
||||||
xhci_dbg(xhci, "Freed event ring\n");
|
xhci_dbg(xhci, "Freed event ring\n");
|
||||||
|
|
||||||
xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
|
|
||||||
if (xhci->cmd_ring)
|
if (xhci->cmd_ring)
|
||||||
xhci_ring_free(xhci, xhci->cmd_ring);
|
xhci_ring_free(xhci, xhci->cmd_ring);
|
||||||
xhci->cmd_ring = NULL;
|
xhci->cmd_ring = NULL;
|
||||||
|
@ -1841,7 +1835,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
||||||
xhci->medium_streams_pool = NULL;
|
xhci->medium_streams_pool = NULL;
|
||||||
xhci_dbg(xhci, "Freed medium stream array pool\n");
|
xhci_dbg(xhci, "Freed medium stream array pool\n");
|
||||||
|
|
||||||
xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
|
|
||||||
if (xhci->dcbaa)
|
if (xhci->dcbaa)
|
||||||
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
|
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
|
||||||
xhci->dcbaa, xhci->dcbaa->dma);
|
xhci->dcbaa, xhci->dcbaa->dma);
|
||||||
|
@ -2459,6 +2452,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
xhci_warn(xhci, "Couldn't initialize memory\n");
|
xhci_warn(xhci, "Couldn't initialize memory\n");
|
||||||
|
xhci_halt(xhci);
|
||||||
|
xhci_reset(xhci);
|
||||||
xhci_mem_cleanup(xhci);
|
xhci_mem_cleanup(xhci);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||||
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
|
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
|
||||||
}
|
}
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_VIA)
|
||||||
|
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called during probe() after chip reset completes */
|
/* called during probe() after chip reset completes */
|
||||||
|
@ -326,7 +328,7 @@ int __init xhci_register_pci(void)
|
||||||
return pci_register_driver(&xhci_pci_driver);
|
return pci_register_driver(&xhci_pci_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit xhci_unregister_pci(void)
|
void xhci_unregister_pci(void)
|
||||||
{
|
{
|
||||||
pci_unregister_driver(&xhci_pci_driver);
|
pci_unregister_driver(&xhci_pci_driver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2417,7 +2417,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||||
u32 irq_pending;
|
u32 irq_pending;
|
||||||
/* Acknowledge the PCI interrupt */
|
/* Acknowledge the PCI interrupt */
|
||||||
irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
||||||
irq_pending |= 0x3;
|
irq_pending |= IMAN_IP;
|
||||||
xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
|
xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2734,7 +2734,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||||
urb->dev->speed == USB_SPEED_FULL)
|
urb->dev->speed == USB_SPEED_FULL)
|
||||||
urb->interval /= 8;
|
urb->interval /= 8;
|
||||||
}
|
}
|
||||||
return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
|
return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3514,7 +3514,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||||
}
|
}
|
||||||
ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
|
ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
|
||||||
|
|
||||||
return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
|
return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** Command Ring Operations ****/
|
/**** Command Ring Operations ****/
|
||||||
|
|
|
@ -106,6 +106,9 @@ int xhci_halt(struct xhci_hcd *xhci)
|
||||||
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
|
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
xhci->xhc_state |= XHCI_STATE_HALTED;
|
xhci->xhc_state |= XHCI_STATE_HALTED;
|
||||||
|
else
|
||||||
|
xhci_warn(xhci, "Host not halted after %u microseconds.\n",
|
||||||
|
XHCI_MAX_HALT_USEC);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,11 +667,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci)
|
||||||
xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
|
xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
|
||||||
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
||||||
xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
|
xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
|
||||||
xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
|
||||||
xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
|
|
||||||
xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
|
xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
|
||||||
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
|
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
|
||||||
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||||
|
xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
||||||
|
xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xhci_restore_registers(struct xhci_hcd *xhci)
|
static void xhci_restore_registers(struct xhci_hcd *xhci)
|
||||||
|
@ -677,10 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
|
||||||
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
|
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
|
||||||
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
|
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
|
||||||
xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
|
xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
|
||||||
xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
|
|
||||||
xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
|
|
||||||
xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
|
xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
|
||||||
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
|
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
|
||||||
|
xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
|
||||||
|
xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
|
||||||
|
xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
|
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
|
||||||
|
|
|
@ -205,6 +205,10 @@ struct xhci_op_regs {
|
||||||
#define CMD_PM_INDEX (1 << 11)
|
#define CMD_PM_INDEX (1 << 11)
|
||||||
/* bits 12:31 are reserved (and should be preserved on writes). */
|
/* bits 12:31 are reserved (and should be preserved on writes). */
|
||||||
|
|
||||||
|
/* IMAN - Interrupt Management Register */
|
||||||
|
#define IMAN_IP (1 << 1)
|
||||||
|
#define IMAN_IE (1 << 0)
|
||||||
|
|
||||||
/* USBSTS - USB status - status bitmasks */
|
/* USBSTS - USB status - status bitmasks */
|
||||||
/* HC not running - set to 1 when run/stop bit is cleared. */
|
/* HC not running - set to 1 when run/stop bit is cleared. */
|
||||||
#define STS_HALT XHCI_STS_HALT
|
#define STS_HALT XHCI_STS_HALT
|
||||||
|
|
|
@ -60,8 +60,6 @@ static int usb_serial_device_probe(struct device *dev)
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (port->dev_state != PORT_REGISTERING)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
driver = port->serial->type;
|
driver = port->serial->type;
|
||||||
if (driver->port_probe) {
|
if (driver->port_probe) {
|
||||||
|
@ -98,9 +96,6 @@ static int usb_serial_device_remove(struct device *dev)
|
||||||
if (!port)
|
if (!port)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (port->dev_state != PORT_UNREGISTERING)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
device_remove_file(&port->dev, &dev_attr_port_number);
|
device_remove_file(&port->dev, &dev_attr_port_number);
|
||||||
|
|
||||||
driver = port->serial->type;
|
driver = port->serial->type;
|
||||||
|
|
|
@ -75,7 +75,8 @@ struct ftdi_private {
|
||||||
unsigned long last_dtr_rts; /* saved modem control outputs */
|
unsigned long last_dtr_rts; /* saved modem control outputs */
|
||||||
struct async_icount icount;
|
struct async_icount icount;
|
||||||
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
||||||
char prev_status, diff_status; /* Used for TIOCMIWAIT */
|
char prev_status; /* Used for TIOCMIWAIT */
|
||||||
|
bool dev_gone; /* Used to abort TIOCMIWAIT */
|
||||||
char transmit_empty; /* If transmitter is empty or not */
|
char transmit_empty; /* If transmitter is empty or not */
|
||||||
struct usb_serial_port *port;
|
struct usb_serial_port *port;
|
||||||
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
|
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
|
||||||
|
@ -1681,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
||||||
init_waitqueue_head(&priv->delta_msr_wait);
|
init_waitqueue_head(&priv->delta_msr_wait);
|
||||||
|
|
||||||
priv->flags = ASYNC_LOW_LATENCY;
|
priv->flags = ASYNC_LOW_LATENCY;
|
||||||
|
priv->dev_gone = false;
|
||||||
|
|
||||||
if (quirk && quirk->port_probe)
|
if (quirk && quirk->port_probe)
|
||||||
quirk->port_probe(priv);
|
quirk->port_probe(priv);
|
||||||
|
@ -1839,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
||||||
|
|
||||||
dbg("%s", __func__);
|
dbg("%s", __func__);
|
||||||
|
|
||||||
|
priv->dev_gone = true;
|
||||||
|
wake_up_interruptible_all(&priv->delta_msr_wait);
|
||||||
|
|
||||||
remove_sysfs_attrs(port);
|
remove_sysfs_attrs(port);
|
||||||
|
|
||||||
kref_put(&priv->kref, ftdi_sio_priv_release);
|
kref_put(&priv->kref, ftdi_sio_priv_release);
|
||||||
|
@ -1982,17 +1987,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
|
||||||
N.B. packet may be processed more than once, but differences
|
N.B. packet may be processed more than once, but differences
|
||||||
are only processed once. */
|
are only processed once. */
|
||||||
status = packet[0] & FTDI_STATUS_B0_MASK;
|
status = packet[0] & FTDI_STATUS_B0_MASK;
|
||||||
if (status & FTDI_RS0_CTS)
|
|
||||||
priv->icount.cts++;
|
|
||||||
if (status & FTDI_RS0_DSR)
|
|
||||||
priv->icount.dsr++;
|
|
||||||
if (status & FTDI_RS0_RI)
|
|
||||||
priv->icount.rng++;
|
|
||||||
if (status & FTDI_RS0_RLSD)
|
|
||||||
priv->icount.dcd++;
|
|
||||||
if (status != priv->prev_status) {
|
if (status != priv->prev_status) {
|
||||||
priv->diff_status |= status ^ priv->prev_status;
|
char diff_status = status ^ priv->prev_status;
|
||||||
wake_up_interruptible(&priv->delta_msr_wait);
|
|
||||||
|
if (diff_status & FTDI_RS0_CTS)
|
||||||
|
priv->icount.cts++;
|
||||||
|
if (diff_status & FTDI_RS0_DSR)
|
||||||
|
priv->icount.dsr++;
|
||||||
|
if (diff_status & FTDI_RS0_RI)
|
||||||
|
priv->icount.rng++;
|
||||||
|
if (diff_status & FTDI_RS0_RLSD)
|
||||||
|
priv->icount.dcd++;
|
||||||
|
|
||||||
|
wake_up_interruptible_all(&priv->delta_msr_wait);
|
||||||
priv->prev_status = status;
|
priv->prev_status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2395,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
||||||
*/
|
*/
|
||||||
case TIOCMIWAIT:
|
case TIOCMIWAIT:
|
||||||
cprev = priv->icount;
|
cprev = priv->icount;
|
||||||
while (1) {
|
while (!priv->dev_gone) {
|
||||||
interruptible_sleep_on(&priv->delta_msr_wait);
|
interruptible_sleep_on(&priv->delta_msr_wait);
|
||||||
/* see if a signal did it */
|
/* see if a signal did it */
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
cnow = priv->icount;
|
cnow = priv->icount;
|
||||||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
|
||||||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
|
||||||
return -EIO; /* no change => error */
|
|
||||||
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
||||||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
||||||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
|
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
|
||||||
|
@ -2412,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty,
|
||||||
}
|
}
|
||||||
cprev = cnow;
|
cprev = cnow;
|
||||||
}
|
}
|
||||||
/* not reached */
|
return -EIO;
|
||||||
break;
|
break;
|
||||||
case TIOCSERGETLSR:
|
case TIOCSERGETLSR:
|
||||||
return get_lsr_info(port, (struct serial_struct __user *)arg);
|
return get_lsr_info(port, (struct serial_struct __user *)arg);
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
|
|
||||||
/* Product information. */
|
/* Product information. */
|
||||||
#define FOCUS_VENDOR_ID 0x0C2E
|
#define FOCUS_VENDOR_ID 0x0C2E
|
||||||
#define FOCUS_PRODUCT_ID 0x0720
|
#define FOCUS_PRODUCT_ID_BI 0x0720
|
||||||
#define FOCUS_PRODUCT_ID_UNI 0x0710
|
#define FOCUS_PRODUCT_ID_UNI 0x0700
|
||||||
|
|
||||||
#define METROUSB_SET_REQUEST_TYPE 0x40
|
#define METROUSB_SET_REQUEST_TYPE 0x40
|
||||||
#define METROUSB_SET_MODEM_CTRL_REQUEST 10
|
#define METROUSB_SET_MODEM_CTRL_REQUEST 10
|
||||||
|
@ -47,7 +47,7 @@ struct metrousb_private {
|
||||||
|
|
||||||
/* Device table list. */
|
/* Device table list. */
|
||||||
static struct usb_device_id id_table[] = {
|
static struct usb_device_id id_table[] = {
|
||||||
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID) },
|
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
|
||||||
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
|
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
|
||||||
{ }, /* Terminating entry. */
|
{ }, /* Terminating entry. */
|
||||||
};
|
};
|
||||||
|
|
|
@ -708,6 +708,7 @@ static const struct usb_device_id option_ids[] = {
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) },
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) },
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) },
|
||||||
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) },
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) },
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) },
|
||||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) },
|
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) },
|
||||||
|
|
|
@ -420,7 +420,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
||||||
control = priv->line_control;
|
control = priv->line_control;
|
||||||
if ((cflag & CBAUD) == B0)
|
if ((cflag & CBAUD) == B0)
|
||||||
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
|
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
|
||||||
else
|
else if ((old_termios->c_cflag & CBAUD) == B0)
|
||||||
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
|
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
|
||||||
if (control != priv->line_control) {
|
if (control != priv->line_control) {
|
||||||
control = priv->line_control;
|
control = priv->line_control;
|
||||||
|
|
|
@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = {
|
||||||
{ USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
|
{ USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
|
||||||
{ USB_DEVICE(0x1199, 0x6859) }, /* Sierra Wireless AirCard 885 E */
|
{ USB_DEVICE(0x1199, 0x6859) }, /* Sierra Wireless AirCard 885 E */
|
||||||
{ USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
|
{ USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
|
||||||
|
{ USB_DEVICE(0x1199, 0x68A2) }, /* Sierra Wireless MC7710 */
|
||||||
/* Sierra Wireless C885 */
|
/* Sierra Wireless C885 */
|
||||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
|
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
|
||||||
/* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
|
/* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
|
||||||
|
|
|
@ -1059,6 +1059,12 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
serial->attached = 1;
|
serial->attached = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Avoid race with tty_open and serial_install by setting the
|
||||||
|
* disconnected flag and not clearing it until all ports have been
|
||||||
|
* registered.
|
||||||
|
*/
|
||||||
|
serial->disconnected = 1;
|
||||||
|
|
||||||
if (get_free_serial(serial, num_ports, &minor) == NULL) {
|
if (get_free_serial(serial, num_ports, &minor) == NULL) {
|
||||||
dev_err(&interface->dev, "No more free serial devices\n");
|
dev_err(&interface->dev, "No more free serial devices\n");
|
||||||
goto probe_error;
|
goto probe_error;
|
||||||
|
@ -1070,19 +1076,16 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
port = serial->port[i];
|
port = serial->port[i];
|
||||||
dev_set_name(&port->dev, "ttyUSB%d", port->number);
|
dev_set_name(&port->dev, "ttyUSB%d", port->number);
|
||||||
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
|
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
|
||||||
port->dev_state = PORT_REGISTERING;
|
|
||||||
device_enable_async_suspend(&port->dev);
|
device_enable_async_suspend(&port->dev);
|
||||||
|
|
||||||
retval = device_add(&port->dev);
|
retval = device_add(&port->dev);
|
||||||
if (retval) {
|
if (retval)
|
||||||
dev_err(&port->dev, "Error registering port device, "
|
dev_err(&port->dev, "Error registering port device, "
|
||||||
"continuing\n");
|
"continuing\n");
|
||||||
port->dev_state = PORT_UNREGISTERED;
|
|
||||||
} else {
|
|
||||||
port->dev_state = PORT_REGISTERED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serial->disconnected = 0;
|
||||||
|
|
||||||
usb_serial_console_init(debug, minor);
|
usb_serial_console_init(debug, minor);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
|
@ -1124,22 +1127,8 @@ void usb_serial_disconnect(struct usb_interface *interface)
|
||||||
}
|
}
|
||||||
kill_traffic(port);
|
kill_traffic(port);
|
||||||
cancel_work_sync(&port->work);
|
cancel_work_sync(&port->work);
|
||||||
if (port->dev_state == PORT_REGISTERED) {
|
if (device_is_registered(&port->dev))
|
||||||
|
|
||||||
/* Make sure the port is bound so that the
|
|
||||||
* driver's port_remove method is called.
|
|
||||||
*/
|
|
||||||
if (!port->dev.driver) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
port->dev.driver =
|
|
||||||
&serial->type->driver;
|
|
||||||
rc = device_bind_driver(&port->dev);
|
|
||||||
}
|
|
||||||
port->dev_state = PORT_UNREGISTERING;
|
|
||||||
device_del(&port->dev);
|
device_del(&port->dev);
|
||||||
port->dev_state = PORT_UNREGISTERED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serial->type->disconnect(serial);
|
serial->type->disconnect(serial);
|
||||||
|
|
|
@ -132,6 +132,35 @@ static struct us_unusual_dev for_dynamic_ids =
|
||||||
#undef COMPLIANT_DEV
|
#undef COMPLIANT_DEV
|
||||||
#undef USUAL_DEV
|
#undef USUAL_DEV
|
||||||
|
|
||||||
|
#ifdef CONFIG_LOCKDEP
|
||||||
|
|
||||||
|
static struct lock_class_key us_interface_key[USB_MAXINTERFACES];
|
||||||
|
|
||||||
|
static void us_set_lock_class(struct mutex *mutex,
|
||||||
|
struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
struct usb_device *udev = interface_to_usbdev(intf);
|
||||||
|
struct usb_host_config *config = udev->actconfig;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < config->desc.bNumInterfaces; i++) {
|
||||||
|
if (config->interface[i] == intf)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(i == config->desc.bNumInterfaces);
|
||||||
|
|
||||||
|
lockdep_set_class(mutex, &us_interface_key[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void us_set_lock_class(struct mutex *mutex,
|
||||||
|
struct usb_interface *intf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PM /* Minimal support for suspend and resume */
|
#ifdef CONFIG_PM /* Minimal support for suspend and resume */
|
||||||
|
|
||||||
|
@ -895,6 +924,7 @@ int usb_stor_probe1(struct us_data **pus,
|
||||||
*pus = us = host_to_us(host);
|
*pus = us = host_to_us(host);
|
||||||
memset(us, 0, sizeof(struct us_data));
|
memset(us, 0, sizeof(struct us_data));
|
||||||
mutex_init(&(us->dev_mutex));
|
mutex_init(&(us->dev_mutex));
|
||||||
|
us_set_lock_class(&us->dev_mutex, intf);
|
||||||
init_completion(&us->cmnd_ready);
|
init_completion(&us->cmnd_ready);
|
||||||
init_completion(&(us->notify));
|
init_completion(&(us->notify));
|
||||||
init_waitqueue_head(&us->delay_wait);
|
init_waitqueue_head(&us->delay_wait);
|
||||||
|
|
|
@ -28,13 +28,6 @@
|
||||||
/* parity check flag */
|
/* parity check flag */
|
||||||
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||||
|
|
||||||
enum port_dev_state {
|
|
||||||
PORT_UNREGISTERED,
|
|
||||||
PORT_REGISTERING,
|
|
||||||
PORT_REGISTERED,
|
|
||||||
PORT_UNREGISTERING,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* USB serial flags */
|
/* USB serial flags */
|
||||||
#define USB_SERIAL_WRITE_BUSY 0
|
#define USB_SERIAL_WRITE_BUSY 0
|
||||||
|
|
||||||
|
@ -124,7 +117,6 @@ struct usb_serial_port {
|
||||||
char throttle_req;
|
char throttle_req;
|
||||||
unsigned long sysrq; /* sysrq timeout */
|
unsigned long sysrq; /* sysrq timeout */
|
||||||
struct device dev;
|
struct device dev;
|
||||||
enum port_dev_state dev_state;
|
|
||||||
};
|
};
|
||||||
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
|
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue