From 72887c8644384c0cc43b9298ae0659de383f2e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Mon, 30 May 2011 20:45:42 +0200 Subject: usb: musb: host: compare status for negative error values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variable d is a struct usb_iso_packet_descriptor. The status filed is usually negative when an error happens. Signed-off-by: Márton Németh Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 7295e31..8b2473f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1575,7 +1575,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* even if there was an error, we did the dma * for iso_frame_desc->length */ - if (d->status != EILSEQ && d->status != -EOVERFLOW) + if (d->status != -EILSEQ && d->status != -EOVERFLOW) d->status = 0; if (++qh->iso_idx >= urb->number_of_packets) -- cgit v1.1 From 4858f06e7d92ed2ebdb29ccbc079c127e675a89c Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta Date: Wed, 8 Jun 2011 17:12:02 +0300 Subject: usb: musb: gadget: clear TXPKTRDY flag when set FLUSHFIFO Fixes mis-use of MUSB's hardware feature where it won't flush FIFOs when TXPKTRDY flag was set before and we are flushing setting both FLUSHFIFO and TXPKTRDY. In other words, we need to ensure that when we try to flush FIFOs, we don't accidentaly set TXPKTRDY bit too due to a read-back of the register. The MUSB Programming Guide says "May be set simultaneously with TxPktRdy to abort the packet that is currently being loaded into the FIFO". This is a situation where TXPKTRDY hasn't been set yet, but some data already loaded into the fifo. It looks, that if TXPKTRDY has been set before, and there is no loading in progress, but we set FLUSHFIFO with the TXPKTRDY, controller tries to use the same logic to abort loading and as the result just does nothing (because there is no packet been loaded currently) Signed-off-by: Yauheni Kaliuta [ balbi@ti.com : fixed one whitespace git complained about improved the commit log slightly ] Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 0a50a35..6aeb363 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1524,6 +1524,12 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep) csr = musb_readw(epio, MUSB_TXCSR); if (csr & MUSB_TXCSR_FIFONOTEMPTY) { csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS; + /* + * Setting both TXPKTRDY and FLUSHFIFO makes controller + * to interrupt current FIFO loading, but not flushing + * the already loaded ones. + */ + csr &= ~MUSB_TXCSR_TXPKTRDY; musb_writew(epio, MUSB_TXCSR, csr); /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ musb_writew(epio, MUSB_TXCSR, csr); -- cgit v1.1 From 357f45db920393aac983a137bd74095f612d5a01 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 13 Jun 2011 22:50:41 +0200 Subject: USB: TI 3410/5052 USB Serial Driver: Fix mem leak when firmware is too big. If the size of the firmware exceeds TI_FIRMWARE_BUF_SIZE we'll leak 'fw_p' by failing to call release_firmware(). This patch fixes the leak. Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ti_usb_3410_5052.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index c6d92a5..ea84456 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1745,6 +1745,7 @@ static int ti_download_firmware(struct ti_device *tdev) } if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); + release_firmware(fw_p); return -ENOENT; } -- cgit v1.1 From fa75ac379e63c2864e9049b5e8615e40f65c1e70 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Sun, 5 Jun 2011 23:10:04 -0700 Subject: xhci: Reject double add of active endpoints. While trying to switch a UAS device from the BOT configuration to the UAS configuration via the bConfigurationValue file, Tanya ran into an issue in the USB core. usb_disable_device() sets entries in udev->ep_out and udev->ep_out to NULL, but doesn't call into the xHCI bandwidth management functions to remove the BOT configuration endpoints from the xHCI host's internal structures. The USB core would then attempt to add endpoints for the UAS configuration, and some of the endpoints had the same address as endpoints in the BOT configuration. The xHCI driver blindly added the endpoints again, but the xHCI host controller rejected the Configure Endpoint command because active endpoints were added without being dropped. Make the xHCI driver reject calls to xhci_add_endpoint() that attempt to add active endpoints without first calling xhci_drop_endpoint(). This should be backported to kernels as old as 2.6.31. Signed-off-by: Sarah Sharp Reported-by: Tanya Brokhman Cc: stable@kernel.org --- drivers/usb/host/xhci.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 06e7023..e5a0171 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1401,6 +1401,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, u32 added_ctxs; unsigned int last_ctx; u32 new_add_flags, new_drop_flags, new_slot_info; + struct xhci_virt_device *virt_dev; int ret = 0; ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); @@ -1425,11 +1426,25 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, return 0; } - in_ctx = xhci->devs[udev->slot_id]->in_ctx; - out_ctx = xhci->devs[udev->slot_id]->out_ctx; + virt_dev = xhci->devs[udev->slot_id]; + in_ctx = virt_dev->in_ctx; + out_ctx = virt_dev->out_ctx; ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); + + /* If this endpoint is already in use, and the upper layers are trying + * to add it again without dropping it, reject the addition. + */ + if (virt_dev->eps[ep_index].ring && + !(le32_to_cpu(ctrl_ctx->drop_flags) & + xhci_get_endpoint_flag(&ep->desc))) { + xhci_warn(xhci, "Trying to add endpoint 0x%x " + "without dropping it.\n", + (unsigned int) ep->desc.bEndpointAddress); + return -EINVAL; + } + /* If the HCD has already noted the endpoint is enabled, * ignore this request. */ @@ -1445,8 +1460,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, * process context, not interrupt context (or so documenation * for usb_set_interface() and usb_set_configuration() claim). */ - if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id], - udev, ep, GFP_NOIO) < 0) { + if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) { dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", __func__, ep->desc.bEndpointAddress); return -ENOMEM; -- cgit v1.1 From fccf4e86200b8f5edd9a65da26f150e32ba79808 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Sun, 5 Jun 2011 23:22:22 -0700 Subject: USB: Free bandwidth when usb_disable_device is called. Tanya ran into an issue when trying to switch a UAS device from the BOT configuration to the UAS configuration via the bConfigurationValue sysfs file. Before installing the UAS configuration, set_bConfigurationValue() calls usb_disable_device(). That function is supposed to remove all host controller resources associated with that device, but it leaves some state in the xHCI host controller. Commit 0791971ba8fbc44e4f476079f856335ed45e6324 usb: allow drivers to use allocated bandwidth until unbound added a call to usb_disable_device() in usb_set_configuration(), before the xHCI bandwidth functions were invoked. That commit fixed a bug, but also introduced a bug that is triggered when a configured device is switched to a new configuration. usb_disable_device() goes through all the motions of unbinding the drivers attached to active interfaces and removing the USB core structures associated with those interfaces, but it doesn't actually remove the endpoints from the internal xHCI host controller bandwidth structures. When usb_disable_device() calls usb_disable_endpoint() with reset_hardware set to true, the entries in udev->ep_out and udev->ep_in will be set to NULL. Usually, when the USB core installs a new configuration, usb_hcd_alloc_bandwidth() will drop all non-NULL endpoints in udev->ep_out and udev->ep_in before adding any new endpoints. However, when the new UAS configuration was added, all those entries were null, so none of the old endpoints in the BOT configuration were dropped. The xHCI driver blindly added the UAS configuration endpoints, and some of the endpoint addresses overlapped with the old BOT configuration endpoints. This caused the xHCI host to reject the Configure Endpoint command. Now that the xHCI driver code is cleaned up to reject a double-add of active endpoints, we need to fix the USB core to properly drop old endpoints in usb_disable_device(). If the host controller driver needs bandwidth checking support, make usb_disable_device() call usb_disable_endpoint() with reset_hardware set to false, drop the endpoints from the xHCI host controller, and then call usb_disable_endpoint() again with reset_hardware set to true. The first call to usb_disable_endpoint() will cancel any pending URBs and wait on them to be freed in usb_hcd_disable_endpoint(), but will keep the pointers in udev->ep_out and udev->ep in intact. Then usb_hcd_alloc_bandwidth() will use those pointers to know which endpoints to drop. The final call to usb_disable_endpoint() will do two things: 1. It will call usb_hcd_disable_endpoint() again, which should be harmless since the ep->urb_list should be empty after the first call to usb_disable_endpoint() returns. 2. It will set the entries in udev->ep_out and udev->ep in to NULL, and call usb_hcd_disable_endpoint(). That call will have no effect, since the xHCI driver doesn't set the endpoint_disable function pointer. Note that usb_disable_device() will now need to be called with hcd->bandwidth_mutex held. This should be backported to kernels as old as 2.6.32. Signed-off-by: Sarah Sharp Reported-by: Tanya Brokhman Cc: ablay@codeaurora.org Cc: Alan Stern Cc: stable@kernel.org --- drivers/usb/core/hub.c | 3 +++ drivers/usb/core/message.c | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 90ae175..ca339bc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1634,6 +1634,7 @@ void usb_disconnect(struct usb_device **pdev) { struct usb_device *udev = *pdev; int i; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); if (!udev) { pr_debug ("%s nodev\n", __func__); @@ -1661,7 +1662,9 @@ void usb_disconnect(struct usb_device **pdev) * so that the hardware is now fully quiesced. */ dev_dbg (&udev->dev, "unregistering device\n"); + mutex_lock(hcd->bandwidth_mutex); usb_disable_device(udev, 0); + mutex_unlock(hcd->bandwidth_mutex); usb_hcd_synchronize_unlinks(udev); usb_remove_ep_devs(&udev->ep0); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5701e85..64c7ab4 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1135,10 +1135,13 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf, * Deallocates hcd/hardware state for the endpoints (nuking all or most * pending urbs) and usbcore state for the interfaces, so that usbcore * must usb_set_configuration() before any interfaces could be used. + * + * Must be called with hcd->bandwidth_mutex held. */ void usb_disable_device(struct usb_device *dev, int skip_ep0) { int i; + struct usb_hcd *hcd = bus_to_hcd(dev->bus); /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -1172,6 +1175,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__, skip_ep0 ? "non-ep0" : "all"); + if (hcd->driver->check_bandwidth) { + /* First pass: Cancel URBs, leave endpoint pointers intact. */ + for (i = skip_ep0; i < 16; ++i) { + usb_disable_endpoint(dev, i, false); + usb_disable_endpoint(dev, i + USB_DIR_IN, false); + } + /* Remove endpoints from the host controller internal state */ + usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + /* Second pass: remove endpoint pointers */ + } for (i = skip_ep0; i < 16; ++i) { usb_disable_endpoint(dev, i, true); usb_disable_endpoint(dev, i + USB_DIR_IN, true); @@ -1727,6 +1740,7 @@ free_interfaces: /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ + mutex_lock(hcd->bandwidth_mutex); if (dev->state != USB_STATE_ADDRESS) usb_disable_device(dev, 1); /* Skip ep0 */ @@ -1739,7 +1753,6 @@ free_interfaces: * host controller will not allow submissions to dropped endpoints. If * this call fails, the device state is unchanged. */ - mutex_lock(hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { mutex_unlock(hcd->bandwidth_mutex); -- cgit v1.1 From d23336329fa4c157ed6256d4279a73b87486a1b6 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 6 Jun 2011 00:53:47 -0700 Subject: xhci: Don't warn about zeroed bMaxBurst descriptor field. The USB 3.0 specification says that the bMaxBurst field in the SuperSpeed Endpoint Companion descriptor is supposed to indicate how many packets a SS device can handle before it needs to wait for an explicit handshake from the host controller. A zero value means the device can only handle one packet before it needs a handshake. Remove a warning in the xHCI driver that implies this is an invalid value. Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-mem.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0f8e1d2..fcb7f7e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1215,8 +1215,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); /* dig out max burst from ep companion desc */ max_packet = ep->ss_ep_comp.bMaxBurst; - if (!max_packet) - xhci_warn(xhci, "WARN no SS endpoint bMaxBurst\n"); ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet)); break; case USB_SPEED_HIGH: -- cgit v1.1 From e1cf486d881d853d710e2d86a7adfc5fd260990f Mon Sep 17 00:00:00 2001 From: Alex He Date: Fri, 3 Jun 2011 15:58:25 +0800 Subject: xHCI 1.0: Force Stopped Event(FSE) FSE shall occur on the TD natural boundary. The software ep_ring dequeue pointer exceed the hardware ep_ring dequeue pointer in these cases of Table-3. As a result, the event_trb(pointed by hardware dequeue pointer) of the FSE can't be found in the current TD(pointed by software dequeue pointer). What should we do is to figured out the FSE case and skip over it. Signed-off-by: Alex He Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 800f417..0c00849 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2063,6 +2063,20 @@ static int handle_tx_event(struct xhci_hcd *xhci, /* Is this a TRB in the currently executing TD? */ event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, td->last_trb, event_dma); + + /* + * Skip the Force Stopped Event. The event_trb(event_dma) of FSE + * is not in the current TD pointed by ep_ring->dequeue because + * that the hardware dequeue pointer still at the previous TRB + * of the current TD. The previous TRB maybe a Link TD or the + * last TRB of the previous TD. The command completion handle + * will take care the rest. + */ + if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { + ret = 0; + goto cleanup; + } + if (!event_seg) { if (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { -- cgit v1.1 From 578333ab95f70db13951d30a9ad6b565b61639a9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jun 2011 16:32:46 -0400 Subject: USB: change maintainership of ohci-hcd and ehci-hcd Following the loss of David Brownell, I volunteer to maintain the ohci-hcd and ehci-hcd drivers. This patch (as1472) makes it official. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 4 ++++ drivers/usb/host/ohci-hcd.c | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b435ed6..f8030ee 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1,4 +1,8 @@ /* + * Enhanced Host Controller Interface (EHCI) driver for USB. + * + * Maintainer: Alan Stern + * * Copyright (c) 2000-2004 by David Brownell * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9aa10bd..f9cf3f0 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1,5 +1,7 @@ /* - * OHCI HCD (Host Controller Driver) for USB. + * Open Host Controller Interface (OHCI) driver for USB. + * + * Maintainer: Alan Stern * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2004 David Brownell -- cgit v1.1 From cbb330045e5df8f665ac60227ff898421fc8fb92 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jun 2011 16:29:16 -0400 Subject: USB: don't let the hub driver prevent system sleep This patch (as1465) continues implementation of the policy that errors during suspend or hibernation should not prevent the system from going to sleep. In this case, failure to turn on the Suspend feature for a hub port shouldn't be reported as an error. There are situations where this does actually occur (such as when the device plugged into that port was disconnected in the recent past), and it turns out to be harmless. There's no reason for it to prevent a system sleep. Also, don't allow the hub driver to fail a system suspend if the downstream ports aren't all suspended. This is also harmless (and should never happen, given the change mentioned above); printing a warning message in the kernel log is all we really need to do. Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 90ae175..c2ac087 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2362,6 +2362,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + + /* System sleep transitions should never fail */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; } else { /* device has up to 10 msec to fully suspend */ dev_dbg(&udev->dev, "usb %ssuspend\n", @@ -2611,16 +2615,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) struct usb_device *hdev = hub->hdev; unsigned port1; - /* fail if children aren't already suspended */ + /* Warn if children aren't already suspended */ for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; udev = hdev->children [port1-1]; if (udev && udev->can_submit) { - if (!(msg.event & PM_EVENT_AUTO)) - dev_dbg(&intf->dev, "port %d nyet suspended\n", - port1); - return -EBUSY; + dev_warn(&intf->dev, "port %d nyet suspended\n", port1); + if (msg.event & PM_EVENT_AUTO) + return -EBUSY; } } -- cgit v1.1 From 0af212ba8f123c2eba151af7726c34a50b127962 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jun 2011 16:27:43 -0400 Subject: USB: don't let errors prevent system sleep This patch (as1464) implements the recommended policy that most errors during suspend or hibernation should not prevent the system from going to sleep. In particular, failure to suspend a USB driver or a USB device should not prevent the sleep from succeeding: Failure to suspend a device won't matter, because the device will automatically go into suspend mode when the USB bus stops carrying packets. (This might be less true for USB-3.0 devices, but let's not worry about them now.) Failure of a driver to suspend might lead to trouble later on when the system wakes up, but it isn't sufficient reason to prevent the system from going to sleep. Signed-off-by: Alan Stern CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index e35a176..81add81 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1187,13 +1187,22 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) for (i = n - 1; i >= 0; --i) { intf = udev->actconfig->interface[i]; status = usb_suspend_interface(udev, intf, msg); + + /* Ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; if (status != 0) break; } } - if (status == 0) + if (status == 0) { status = usb_suspend_device(udev, msg); + /* Again, ignore errors during system sleep transitions */ + if (!(msg.event & PM_EVENT_AUTO)) + status = 0; + } + /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); -- cgit v1.1 From f6ba6fe2d913da6707a71a413d6ec8ae98d6ce18 Mon Sep 17 00:00:00 2001 From: Alex He Date: Wed, 8 Jun 2011 18:34:06 +0800 Subject: xHCI 1.0: Incompatible Device Error It is one new TRB Completion Code for the xHCI spec v1.0. Asserted if the xHC detects a problem with a device that does not allow it to be successfully accessed, e.g. due to a device compliance or compatibility problem. This error may be returned by any command or transfer, and is fatal as far as the Slot is concerned. Return -EPROTO by urb->status or frame->status of ISOC for transfer case. And return -ENODEV for configure endpoint command, evaluate context command and address device command if there is an incompatible Device Error. The error codes will be sent back to the USB core to decide how to do. It's unnecessary for other commands because after the three commands run successfully means that the device has been accepted. Signed-off-by: Alex He Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 5 +++++ drivers/usb/host/xhci.c | 15 +++++++++++++++ drivers/usb/host/xhci.h | 2 ++ 3 files changed, 22 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0c00849..436332a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1733,6 +1733,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, frame->status = -EOVERFLOW; skip_td = true; break; + case COMP_DEV_ERR: case COMP_STALL: frame->status = -EPROTO; skip_td = true; @@ -2016,6 +2017,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; + case COMP_DEV_ERR: + xhci_warn(xhci, "WARN: detect an incompatible device"); + status = -EPROTO; + break; case COMP_MISSED_INT: /* * When encounter missed service error, one or more isoc tds diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e5a0171..15eb4c3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1551,6 +1551,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, "and endpoint is not disabled.\n"); ret = -EINVAL; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint " + "configure command.\n"); + ret = -ENODEV; + break; case COMP_SUCCESS: dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); ret = 0; @@ -1585,6 +1590,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate " + "context command.\n"); + ret = -ENODEV; + break; case COMP_MEL_ERR: /* Max Exit Latency too large error */ dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); @@ -2867,6 +2877,11 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) dev_warn(&udev->dev, "Device not responding to set address.\n"); ret = -EPROTO; break; + case COMP_DEV_ERR: + dev_warn(&udev->dev, "ERROR: Incompatible device for address " + "device command.\n"); + ret = -ENODEV; + break; case COMP_SUCCESS: xhci_dbg(xhci, "Successful Address Device command\n"); break; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7d1ea3b..ba90af1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -874,6 +874,8 @@ struct xhci_transfer_event { #define COMP_PING_ERR 20 /* Event Ring is full */ #define COMP_ER_FULL 21 +/* Incompatible Device Error */ +#define COMP_DEV_ERR 22 /* Missed Service Error - HC couldn't service an isoc ep within interval */ #define COMP_MISSED_INT 23 /* Successfully stopped command ring */ -- cgit v1.1 From c877b3b2ad5cb9d4fe523c5496185cc328ff3ae9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 15 Jun 2011 23:47:21 +0200 Subject: xhci: Add reset on resume quirk for asrock p67 host The asrock p67 xhci controller completely dies on resume, add a quirk for this, to bring the host back online after a suspend. This should be backported to stable kernels as old as 2.6.37. Signed-off-by: Maarten Lankhorst Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/host/xhci-pci.c | 8 ++++++++ drivers/usb/host/xhci.c | 2 ++ drivers/usb/host/xhci.h | 1 + 3 files changed, 11 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 17541d0..cb16de2 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -29,6 +29,9 @@ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_VENDOR_ID_ETRON 0x1b6f +#define PCI_DEVICE_ID_ASROCK_P67 0x7023 + static const char hcd_name[] = "xhci_hcd"; /* called after powerup, by probe or system-pm "wakeup" */ @@ -134,6 +137,11 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci->quirks |= XHCI_EP_LIMIT_QUIRK; xhci->limit_active_eps = 64; } + if (pdev->vendor == PCI_VENDOR_ID_ETRON && + pdev->device == PCI_DEVICE_ID_ASROCK_P67) { + xhci->quirks |= XHCI_RESET_ON_RESUME; + xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); + } /* Make sure the HC is halted. */ retval = xhci_halt(xhci); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 15eb4c3..f5fe1ac 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -759,6 +759,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) msleep(100); spin_lock_irq(&xhci->lock); + if (xhci->quirks & XHCI_RESET_ON_RESUME) + hibernated = true; if (!hibernated) { /* step 1: restore register */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ba90af1..d8bbf5c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1310,6 +1310,7 @@ struct xhci_hcd { */ #define XHCI_EP_LIMIT_QUIRK (1 << 5) #define XHCI_BROKEN_MSI (1 << 6) +#define XHCI_RESET_ON_RESUME (1 << 7) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ -- cgit v1.1 From b3df3f9c7df9a8d85e03e158d35487618a160901 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Wed, 15 Jun 2011 19:57:46 -0700 Subject: xhci: Always set urb->status to zero for isoc endpoints. When the xHCI driver encounters a Missed Service Interval event for an isochronous endpoint ring, it means the host controller skipped over one or more isochronous TDs. For TD that is skipped, skip_isoc_td() is called. This sets the frame descriptor status to -EXDEV, and also sets the value stored in the int pointed to by status to -EXDEV. If the isochronous TD happens to be the last TD in an URB, handle_tx_event() will use the status variable to give back the URB to the USB core. That means drivers will see urb->status as -EXDEV. It turns out that EHCI, UHCI, and OHCI always set urb->status to zero for an isochronous urb, regardless of what the frame status is. See itd_complete() in ehci-sched.c: } else { /* URB was too late */ desc->status = -EXDEV; } } /* handle completion now? */ if (likely ((urb_index + 1) != urb->number_of_packets)) goto done; /* ASSERT: it's really the last itd for this urb list_for_each_entry (itd, &stream->td_list, itd_list) BUG_ON (itd->urb == urb); */ /* give urb back to the driver; completion often (re)submits */ dev = urb->dev; ehci_urb_done(ehci, urb, 0); ehci_urb_done() completes the URB with the status of the third argument, which is always zero in this case. It turns out that many USB webcam drivers, such as uvcvideo, cannot handle urb->status set to a non-zero value. They will not resubmit their isochronous URBs in that case, and userspace will see a frozen video. Change the xHCI driver to be consistent with the EHCI and UHCI driver, and always set urb->status to 0 for isochronous URBs. This patch should be backported to kernels as old as 2.6.36 Signed-off-by: Sarah Sharp Cc: "Xu, Andiry" Cc: stable@kernel.org --- drivers/usb/host/xhci-ring.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 436332a..70cacbb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1768,9 +1768,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } } - if ((idx == urb_priv->length - 1) && *status == -EINPROGRESS) - *status = 0; - return finish_td(xhci, td, event_trb, event, ep, status, false); } @@ -1788,8 +1785,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, idx = urb_priv->td_cnt; frame = &td->urb->iso_frame_desc[idx]; - /* The transfer is partly done */ - *status = -EXDEV; + /* The transfer is partly done. */ frame->status = -EXDEV; /* calc actual length */ @@ -2177,6 +2173,11 @@ cleanup: urb->transfer_buffer_length, status); spin_unlock(&xhci->lock); + /* EHCI, UHCI, and OHCI always unconditionally set the + * urb->status of an isochronous endpoint to 0. + */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + status = 0; usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status); spin_lock(&xhci->lock); } -- cgit v1.1 From 8b1ab60c767f33d79894ef66037ef851a7a88fc8 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Fri, 17 Jun 2011 18:45:37 +0200 Subject: usb/isp1760: Fix bug preventing the unlinking of control urbs Both control and bulk transfers use isp1760 slots of type ATL, but the driver unlink code for ATL slots only acts on urbs describing a bulk transfer, letting the code for INT slots take care of the unlink instead, which often ended up removing the interrupt transfer for root hub events instead. That's not good, and gets fixed by this patch. Signed-off-by: Arvid Brodin Cc: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index c9e6e45..55d3d58 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1555,7 +1555,7 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, /* We need to forcefully reclaim the slot since some transfers never return, e.g. interrupt transfers and NAKed bulk transfers. */ - if (usb_pipebulk(urb->pipe)) { + if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); skip_map |= (1 << qh->slot); reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); -- cgit v1.1 From 309427b6351b763917caac3e4b2ab5651df99823 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 17 Jun 2011 17:30:23 +0200 Subject: USB: Add new FT232H chip to drivers/usb/serial/ftdi_sio.c appended patch adds support for the new FTDI FT232H chip. This chip is a single channel version of the dual FT2232H/quad FT4232H, coming with it's own default PID 0x6014 (FT2232H uses the same PID 0x6010 like FT2232C, FT4232H has also it's own PID). The patch was checked on an UM232H module and a terminal program with TX/RX shorted to that typing in the terminal reproduced the characters. Signed-off-by: Uwe Bonnes Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 19 ++++++++++++++----- drivers/usb/serial/ftdi_sio.h | 3 ++- drivers/usb/serial/ftdi_sio_ids.h | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1627289..2e06b90 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -179,6 +179,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -848,7 +849,8 @@ static const char *ftdi_chip_name[] = { [FT2232C] = "FT2232C", [FT232RL] = "FT232RL", [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H" + [FT4232H] = "FT4232H", + [FT232H] = "FT232H" }; @@ -1168,6 +1170,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty, break; case FT2232H: /* FT2232H chip */ case FT4232H: /* FT4232H chip */ + case FT232H: /* FT232H chip */ if ((baud <= 12000000) & (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { @@ -1429,9 +1432,12 @@ static void ftdi_determine_type(struct usb_serial_port *port) } else if (version < 0x600) { /* Assume it's an FT232BM (or FT245BM) */ priv->chip_type = FT232BM; - } else { - /* Assume it's an FT232R */ + } else if (version < 0x900) { + /* Assume it's an FT232RL */ priv->chip_type = FT232RL; + } else { + /* Assume it's an FT232H */ + priv->chip_type = FT232H; } dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); } @@ -1559,7 +1565,8 @@ static int create_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H)) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } @@ -1580,7 +1587,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || - priv->chip_type == FT4232H) { + priv->chip_type == FT4232H || + priv->chip_type == FT232H) { device_remove_file(&port->dev, &dev_attr_latency_timer); } } @@ -2212,6 +2220,7 @@ static int ftdi_tiocmget(struct tty_struct *tty) case FT232RL: case FT2232H: case FT4232H: + case FT232H: len = 2; break; default: diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 213fe3d..19584fa 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -156,7 +156,8 @@ enum ftdi_chip_type { FT2232C = 4, FT232RL = 5, FT2232H = 6, - FT4232H = 7 + FT4232H = 7, + FT232H = 8 }; enum ftdi_sio_baudrate { diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index ab1fcdf..19156d1 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -22,6 +22,7 @@ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ -- cgit v1.1 From c27d5368ef1f7ea40bcd1fb2626f4c99d77e0080 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 20 Jun 2011 17:22:36 +0200 Subject: USB: ehci-ath79: fix a NULL pointer dereference Loading the ehci-hcd module on the ath79 platform causes a NULL pointer dereference: CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == c0252928, ra == c00de968 Oops[#1]: Cpu 0 $ 0 : 00000000 00000070 00000001 00000000 $ 4 : 802cf870 0000117e ffffffff 8019c7bc $ 8 : 0000000a 00000002 00000001 fffffffb $12 : 8026ef20 0000000f ffffff80 802dad3c $16 : 8077a2d4 8077a200 c00f3484 8019ed84 $20 : c00f0000 00000003 000000a0 80262c2c $24 : 00000002 80079da0 $28 : 80788000 80789c80 80262b14 c00de968 Hi : 00000000 Lo : b61f0000 epc : c0252928 __mod_vermagic5+0xc260/0xc7e8 [ehci_hcd] Not tainted ra : c00de968 usb_add_hcd+0x2a4/0x858 [usbcore] Status: 1000c003 KERNEL EXL IE Cause : 00800008 BadVA : 00000000 PrId : 00019374 (MIPS 24Kc) Modules linked in: ehci_hcd(+) pppoe pppox ipt_REJECT xt_TCPMSS ipt_LOG xt_comment xt_multiport xt_mac xt_limit iptable_mangle iptable_filte r ip_tables xt_tcpudp x_tables ppp_async ppp_generic slhc ath mac80211 usbcore nls_base input_polldev crc_ccitt cfg80211 compat input_core a rc4 aes_generic crypto_algapi Process insmod (pid: 379, threadinfo=80788000, task=80ca2180, tls=77fe52d0) Stack : c0253184 80c57d80 80789cac 8077a200 00000001 8019edc0 807fa800 8077a200 8077a290 c00f3484 8019ed84 c00f0000 00000003 000000a0 80262c2c c00de968 802d0000 800878cc c0253228 c02528e4 c0253184 80c57d80 80bf6800 80ca2180 8007b75c 00000000 8077a200 802cf830 802d0000 00000003 fffffff4 00000015 00000348 00000124 800b189c c024bb4c c0255000 801a27e8 c0253228 c02528e4 ... Call Trace: [] __mod_vermagic5+0xc260/0xc7e8 [ehci_hcd] It is caused by: commit c430131a02d677aa708f56342c1565edfdacb3c0 Author: Jan Andersson Date: Tue May 3 20:11:57 2011 +0200 USB: EHCI: Support controllers with big endian capability regs The two first HC capability registers (CAPLENGTH and HCIVERSION) are defined as one 8-bit and one 16-bit register. Most HC implementations have selected to treat these registers as part of a 32-bit register, giving the same layout for both big and small endian systems. This patch adds a new quirk, big_endian_capbase, to support controllers with big endian register interfaces that treat HCIVERSION and CAPLENGTH as individual registers. Signed-off-by: Jan Andersson Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman The reading of the HC capability register has been moved by that commit to a place where the ehci->caps field is not initialized yet. This patch moves the reading of the register back to the original place. Acked-by: Jan Andersson Cc: Alan Stern Signed-off-by: Gabor Juhos Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-ath79.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index 98cc8a1..aa248c2 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -44,7 +44,6 @@ static int ehci_ath79_init(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct platform_device *pdev = to_platform_device(hcd->self.controller); const struct platform_device_id *id; - int hclength; int ret; id = platform_get_device_id(pdev); @@ -53,20 +52,23 @@ static int ehci_ath79_init(struct usb_hcd *hcd) return -EINVAL; } - hclength = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); switch (id->driver_data) { case EHCI_ATH79_IP_V1: ehci->has_synopsys_hc_bug = 1; ehci->caps = hcd->regs; - ehci->regs = hcd->regs + hclength; + ehci->regs = hcd->regs + + HC_LENGTH(ehci, + ehci_readl(ehci, &ehci->caps->hc_capbase)); break; case EHCI_ATH79_IP_V2: hcd->has_tt = 1; ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + hclength; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(ehci, + ehci_readl(ehci, &ehci->caps->hc_capbase)); break; default: -- cgit v1.1 From 87abd0a92c72eea71542d6c972c67e39e584e989 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 21 Jun 2011 13:24:42 +0900 Subject: usb: r8a66597-hcd: fix cannot detect low/full speed device This controller can control "Transaction Translators", but the hcd->has_tt is not set. Since the commit d199c96d41d80a567493e12b8e96ea056a1350c1 ("USB: prevent buggy from crashing the USB stack") has checked it, the driver could not work the low/full speed device. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/r8a66597-hcd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index db6f8b9..4586369 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2517,6 +2517,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev) INIT_LIST_HEAD(&r8a66597->child_device); hcd->rsrc_start = res->start; + hcd->has_tt = 1; ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger); if (ret != 0) { -- cgit v1.1