Merge tag 'usb-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a number of small USB driver fixes for many reported issues.
  Included in here are:

   - usb serial driver corruption and use-after-free fixes

   - usb gadget rndis bugfixes for malicious/buggy host connections

   - typec driver fixes for a load of different tiny reported issues

   - typec mux driver revert for a broken patch in -rc1

   - usb gadget driver fixes for many different reported problems

   - new usb device quirks added

   - usbip tool fixes and some core usbip fixes as well

   - dwc3 driver fixes for minor issues

   - xhci driver fixes for reported problems

   - lots of other tiny usb driver fixes for many tiny issues

  All of these have been in linux-next with no reported issues"

* tag 'usb-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (56 commits)
  USB: core: ratelimit cabling message
  usb: misc: usbio: fix disconnect UAF in client teardown
  Revert "usb: typec: mux: avoid duplicated mux switches"
  USB: chaoskey: Fix slab-use-after-free in chaoskey_release()
  usb: ucsi: huawei_gaokun: move typec_altmode off stack
  usb: typec: tcpci_rt1711h: unregister TCPCI port with devres
  usb: typec: tcpm: Fix VDM type for Enter Mode commands
  usb: typec: ucsi: cancel pending work on system suspend
  usb: typec: class: drop PD lookup reference
  usb: typec: ps883x: Fix DP+USB3 configuration
  usb: xhci: Fix sleep in atomic context in xhci_free_streams()
  xhci: sideband: fix ring sg table pages leak
  usb: gadget: udc: Fix use-after-free in gadget_match_driver
  usb: dwc3: run gadget disconnect from sleepable suspend context
  usb: sl811-hcd: disable controller wakeup on remove
  usb: typec: anx7411: use devm_pm_runtime_enable()
  usb: dwc3: fix dwc3_readl() and dwc3_writel() calls in dwc3_ulpi_setup()
  USB: misc: uss720: unregister parport on probe failure
  usb: gadget: function: rndis: add length check for header
  usb: gadget: function: rndis: add length check to response query
  ...
This commit is contained in:
Linus Torvalds
2026-07-12 12:12:41 -07:00
53 changed files with 463 additions and 205 deletions

View File

@@ -22,7 +22,7 @@ Description:
Reading this attribute gives the state of the DbC. It
can be one of the following states: disabled, enabled,
initialized, connected or configured.
initialized, connected, configured or suspended.
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_idVendor
Date: March 2023

View File

@@ -28055,6 +28055,7 @@ F: include/dt-bindings/usb/
F: include/linux/usb.h
F: include/linux/usb/
F: include/uapi/linux/usb/
F: rust/kernel/usb.rs
USB TYPEC BUS FOR ALTERNATE MODES
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>

View File

@@ -594,7 +594,9 @@ static int uea_send_modem_cmd(struct usb_device *usb,
static void uea_upload_pre_firmware(const struct firmware *fw_entry,
void *context)
{
struct usb_device *usb = context;
struct usb_interface *intf = context;
struct usb_device *usb = interface_to_usbdev(intf);
struct completion *fw_done = usb_get_intfdata(intf);
const u8 *pfw;
u8 value;
u32 crc = 0;
@@ -663,15 +665,17 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry,
uea_err(usb, "firmware is corrupted\n");
err:
release_firmware(fw_entry);
complete(fw_done);
}
/*
* uea_load_firmware - Load usb firmware for pre-firmware devices.
*/
static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
static int uea_load_firmware(struct usb_interface *intf, unsigned int ver)
{
int ret;
char *fw_name = EAGLE_FIRMWARE;
struct usb_device *usb = interface_to_usbdev(intf);
uea_info(usb, "pre-firmware device, uploading firmware\n");
@@ -694,7 +698,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev,
GFP_KERNEL, usb,
GFP_KERNEL, intf,
uea_upload_pre_firmware);
if (ret)
uea_err(usb, "firmware %s is not available\n", fw_name);
@@ -2555,8 +2559,23 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_reset_device(usb);
if (UEA_IS_PREFIRM(id))
return uea_load_firmware(usb, UEA_CHIP_VERSION(id));
if (UEA_IS_PREFIRM(id)) {
struct completion *fw_done;
/* Wait for the firmware load to be done, in .disconnect() */
fw_done = kzalloc_obj(*fw_done);
if (!fw_done)
return -ENOMEM;
init_completion(fw_done);
usb_set_intfdata(intf, fw_done);
ret = uea_load_firmware(intf, UEA_CHIP_VERSION(id));
if (ret)
kfree(fw_done);
return ret;
}
ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver);
if (ret == 0) {
@@ -2586,6 +2605,13 @@ static void uea_disconnect(struct usb_interface *intf)
usbatm_usb_disconnect(intf);
mutex_unlock(&uea_mutex);
uea_info(usb, "ADSL device removed\n");
} else if (usb->config->desc.bNumInterfaces == 1) {
struct completion *fw_done = usb_get_intfdata(intf);
uea_dbg(usb, "pre-firmware device, waiting firmware upload\n");
wait_for_completion(fw_done);
uea_dbg(usb, "pre-firmware device, finished waiting\n");
kfree(fw_done);
}
}

View File

@@ -631,6 +631,8 @@ int cdnsp_alloc_stream_info(struct cdnsp_device *pdev,
}
}
cdnsp_free_stream_ctx(pdev, pep);
cleanup_stream_rings:
kfree(pep->stream_info.stream_rings);

View File

@@ -1816,6 +1816,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */
.driver_info = DISABLE_ECHO, /* DISABLE ECHO in termios flag */
},
{ USB_DEVICE(0x1965, 0x0017), /* Uniden BC125AT */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},

View File

@@ -281,28 +281,24 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
ulpi->dev.parent = dev; /* needed early for ops */
ulpi->dev.bus = &ulpi_bus;
ulpi->dev.type = &ulpi_dev_type;
device_initialize(&ulpi->dev);
dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
ret = ulpi_of_register(ulpi);
if (ret) {
kfree(ulpi);
if (ret)
return ret;
}
ret = ulpi_read_id(ulpi);
if (ret) {
of_node_put(ulpi->dev.of_node);
kfree(ulpi);
if (ret)
return ret;
}
ret = device_register(&ulpi->dev);
if (ret) {
put_device(&ulpi->dev);
ret = device_add(&ulpi->dev);
if (ret)
return ret;
}
root = debugfs_create_dir(dev_name(&ulpi->dev), ulpi_root);
debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops);
@@ -334,9 +330,10 @@ struct ulpi *ulpi_register_interface(struct device *dev,
ulpi->ops = ops;
ret = ulpi_register(dev, ulpi);
if (ret)
if (ret) {
put_device(&ulpi->dev);
return ERR_PTR(ret);
}
return ulpi;
}

View File

@@ -3148,7 +3148,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
delay = HUB_LONG_RESET_TIME;
}
dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
dev_err_ratelimited(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
done:
if (status == 0) {

View File

@@ -296,6 +296,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* CarrolTouch 4500U */
{ USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
/* Samsung T5 EVO Portable SSD */
{ USB_DEVICE(0x04e8, 0x6200), .driver_info = USB_QUIRK_NO_LPM },
/* Samsung Android phone modem - ID conflict with SPH-I500 */
{ USB_DEVICE(0x04e8, 0x6601), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -576,6 +579,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* VLI disk */
{ USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM },
/* VIA Labs, Inc. USB2.0 Hub */
{ USB_DEVICE(0x2109, 0x2817), .driver_info = USB_QUIRK_NO_LPM },
/* Raydium Touchscreen */
{ USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },

View File

@@ -789,9 +789,9 @@ static void dwc3_ulpi_setup(struct dwc3 *dwc)
if (dwc->enable_usb2_transceiver_delay) {
for (index = 0; index < dwc->num_usb2_ports; index++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
reg |= DWC3_GUSB2PHYCFG_XCVRDLY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
}
}
}

View File

@@ -907,35 +907,39 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
ret = priv->drvdata->usb_init(priv);
if (ret)
return ret;
goto err_rearm;
/* Init PHYs */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_init(priv->phys[i]);
if (ret)
return ret;
goto err_rearm;
}
/* Set PHY Power */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_power_on(priv->phys[i]);
if (ret)
return ret;
goto err_rearm;
}
if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
ret = regulator_enable(priv->vbus);
if (ret)
return ret;
goto err_rearm;
}
if (priv->drvdata->usb_post_init) {
ret = priv->drvdata->usb_post_init(priv);
if (ret)
return ret;
goto err_rearm;
}
return 0;
err_rearm:
reset_control_rearm(priv->reset);
return ret;
}
static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {

View File

@@ -3934,15 +3934,48 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
}
}
static bool dwc3_prepare_disconnect_gadget(struct dwc3 *dwc,
struct usb_gadget_driver **driver,
struct usb_gadget **gadget)
{
if (!dwc->async_callbacks || !dwc->gadget_driver ||
!dwc->gadget_driver->disconnect)
return false;
*driver = dwc->gadget_driver;
*gadget = dwc->gadget;
return true;
}
static void dwc3_disconnect_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->disconnect) {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
if (dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->disconnect(dwc->gadget);
driver->disconnect(gadget);
spin_lock(&dwc->lock);
}
}
static void dwc3_disconnect_gadget_sleepable(struct dwc3 *dwc)
{
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
if (!dwc3_prepare_disconnect_gadget(dwc, &driver, &gadget)) {
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
spin_unlock_irqrestore(&dwc->lock, flags);
driver->disconnect(gadget);
}
static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
if (dwc->async_callbacks && dwc->gadget_driver->suspend) {
@@ -4838,7 +4871,6 @@ EXPORT_SYMBOL_GPL(dwc3_gadget_exit);
int dwc3_gadget_suspend(struct dwc3 *dwc)
{
unsigned long flags;
int ret;
ret = dwc3_gadget_soft_disconnect(dwc);
@@ -4852,10 +4884,7 @@ int dwc3_gadget_suspend(struct dwc3 *dwc)
return -EAGAIN;
}
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver)
dwc3_disconnect_gadget(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
dwc3_disconnect_gadget_sleepable(dwc);
return 0;
}

View File

@@ -4267,8 +4267,6 @@ static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
return 0;
fail:
iso_sched_free(stream, sched);
urb->hcpriv = NULL;
return status;
}
@@ -4562,6 +4560,10 @@ static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
else
usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
done_not_linked:
if (status < 0) {
iso_sched_free(stream, urb->hcpriv);
urb->hcpriv = NULL;
}
spin_unlock_irqrestore(&fotg210->lock, flags);
done:
return status;

View File

@@ -1863,9 +1863,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (cdev->config)
config = cdev->config;
else
config = list_first_entry(
config = list_first_entry_or_null(
&cdev->configs,
struct usb_configuration, list);
struct usb_configuration,
list);
if (!config)
goto done;

View File

@@ -288,6 +288,7 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
static void ffs_reset_work(struct work_struct *work);
/* Misc helper functions ****************************************************/
@@ -1374,7 +1375,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
mutex_unlock(&epfile->dmabufs_mutex);
__ffs_epfile_read_buffer_free(epfile);
ffs_data_closed(epfile->ffs);
return 0;
@@ -1704,6 +1704,7 @@ static int ffs_dmabuf_transfer(struct file *file,
resv_dir = epfile->in ? DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE;
dma_resv_add_fence(dmabuf->resv, &fence->base, resv_dir);
dma_fence_put(&fence->base);
dma_resv_unlock(dmabuf->resv);
/* Now that the dma_fence is in place, queue the transfer. */
@@ -2221,6 +2222,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
init_waitqueue_head(&ffs->ev.waitq);
init_waitqueue_head(&ffs->wait);
init_completion(&ffs->ep0req_completion);
INIT_WORK(&ffs->reset_work, ffs_reset_work);
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;
@@ -2364,6 +2366,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfile->name, "ep%u", i);
epfile->in = (ffs->eps_addrmap[i] & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
err = ffs_sb_create_file(ffs->sb, epfile->name,
epfile, &ffs_epfile_operations);
if (err) {
@@ -2389,6 +2392,7 @@ static void ffs_epfiles_destroy(struct super_block *sb,
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
__ffs_epfile_read_buffer_free(epfile);
simple_remove_by_name(root, epfile->name, clear_one);
}
@@ -2453,7 +2457,6 @@ static int ffs_func_eps_enable(struct ffs_function *func)
ret = usb_ep_enable(ep->ep);
if (!ret) {
epfile->ep = ep;
epfile->in = usb_endpoint_dir_in(ep->ep->desc);
epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
} else {
break;
@@ -3775,7 +3778,6 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
spin_unlock_irqrestore(&ffs->eps_lock, flags);
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
@@ -3806,7 +3808,6 @@ static void ffs_func_disable(struct usb_function *f)
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
spin_unlock_irqrestore(&ffs->eps_lock, flags);
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return;
}

View File

@@ -363,12 +363,11 @@ printer_open(struct inode *inode, struct file *fd)
ret = 0;
/* Change the printer status to show that it's on-line. */
dev->printer_status |= PRINTER_SELECTED;
kref_get(&dev->kref);
}
spin_unlock_irqrestore(&dev->lock, flags);
kref_get(&dev->kref);
return ret;
}

View File

@@ -591,6 +591,7 @@ static int rndis_init_response(struct rndis_params *params,
static int rndis_query_response(struct rndis_params *params,
rndis_query_msg_type *buf)
{
u32 BufLength, BufOffset;
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
@@ -598,6 +599,13 @@ static int rndis_query_response(struct rndis_params *params,
if (!params->dev)
return -ENOTSUPP;
BufLength = le32_to_cpu(buf->InformationBufferLength);
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
(BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
(BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
return -EINVAL;
/*
* we need more memory:
* gen_ndis_query_resp expects enough space for
@@ -614,10 +622,8 @@ static int rndis_query_response(struct rndis_params *params,
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
le32_to_cpu(buf->InformationBufferOffset)
+ 8 + (u8 *)buf,
le32_to_cpu(buf->InformationBufferLength),
r)) {
BufOffset + 8 + (u8 *)buf,
BufLength, r)) {
/* OID not supported */
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = cpu_to_le32(sizeof *resp);
@@ -1074,6 +1080,12 @@ int rndis_rm_hdr(struct gether *port,
/* tmp points to a struct rndis_packet_msg_type */
__le32 *tmp = (void *)skb->data;
/* Need at least MessageType, MessageLength, DataOffset, DataLength */
if (skb->len < 16) {
dev_kfree_skb_any(skb);
return -EINVAL;
}
/* MessageType, MessageLength */
if (cpu_to_le32(RNDIS_MSG_PACKET)
!= get_unaligned(tmp++)) {

View File

@@ -31,8 +31,9 @@ static const struct bus_type gadget_bus_type;
/**
* struct usb_udc - describes one usb device controller
* @driver: the gadget driver pointer. For use by the class code
* @dev: the child device to the actual controller
* @gadget: the gadget. For use by the class code
* @gadget_release: the gadget's release routine
* @dev: the child device to the actual controller
* @list: for use by the udc class driver
* @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
@@ -53,6 +54,7 @@ static const struct bus_type gadget_bus_type;
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
void (*gadget_release)(struct device *dev);
struct device dev;
struct list_head list;
bool vbus;
@@ -1362,6 +1364,17 @@ static void usb_udc_nop_release(struct device *dev)
dev_vdbg(dev, "%s\n", __func__);
}
static void usb_gadget_release(struct device *dev)
{
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
struct usb_udc *udc = gadget->udc;
/* Cache the gadget's release routine to prevent UAF */
void (*release)(struct device *dev) = udc->gadget_release;
put_device(&udc->dev);
release(dev);
}
/**
* usb_initialize_gadget - initialize a gadget and its embedded struct device
* @parent: the parent device to this udc. Usually the controller driver's
@@ -1418,6 +1431,14 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_init(&udc->connect_lock);
udc->started = false;
/*
* Align decoupled lifecycles: take a UDC reference to ensure it
* remains allocated until the gadget is released, requiring an
* override of the gadget's release routine to drop it.
*/
udc->gadget_release = gadget->dev.release;
gadget->dev.release = usb_gadget_release;
get_device(&udc->dev);
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
@@ -1462,6 +1483,12 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
/*
* Revert the override and drop the UDC reference to prevent
* leaking the UDC if the gadget was statically allocated.
*/
gadget->dev.release = udc->gadget_release;
put_device(&udc->dev);
err_put_udc:
put_device(&udc->dev);

View File

@@ -1623,6 +1623,7 @@ iso_stream_schedule(
status = 1; /* and give it back immediately */
iso_sched_free(stream, sched);
sched = NULL;
urb->hcpriv = NULL;
}
}
urb->error_count = skip / period;
@@ -1653,8 +1654,6 @@ iso_stream_schedule(
return status;
fail:
iso_sched_free(stream, sched);
urb->hcpriv = NULL;
return status;
}
@@ -1966,6 +1965,10 @@ static int itd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
if (status < 0) {
iso_sched_free(stream, urb->hcpriv);
urb->hcpriv = NULL;
}
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;
@@ -2343,6 +2346,10 @@ static int sitd_submit(struct ehci_hcd *ehci, struct urb *urb,
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
}
done_not_linked:
if (status < 0) {
iso_sched_free(stream, urb->hcpriv);
urb->hcpriv = NULL;
}
spin_unlock_irqrestore(&ehci->lock, flags);
done:
return status;

View File

@@ -1591,6 +1591,7 @@ sl811h_remove(struct platform_device *dev)
remove_debug_file(sl811);
usb_remove_hcd(hcd);
device_wakeup_disable(hcd->self.controller);
/* some platforms may use IORESOURCE_IO */
res = platform_get_resource(dev, IORESOURCE_MEM, 1);

View File

@@ -646,6 +646,31 @@ static int xhci_dbc_enable_dce(struct xhci_dbc *dbc, bool enable)
static void xhci_dbc_set_state(struct xhci_dbc *dbc, enum dbc_state new_state)
{
if (dbc->state == new_state)
return;
switch (new_state) {
case DS_ENABLED:
/*
* DbC pm usage is 1 here, both when moved from disconnect or
* configured states, or when setting initial DbC enable state.
* Just enable pending put
*/
dev_dbg(dbc->dev, "DbC set pending_rpm_put = 1\n");
dbc->pending_rpm_put = 1;
break;
case DS_CONNECTED:
if (dbc->pending_rpm_put)
/* DbC pm usage still 1, just remove pending put */
dbc->pending_rpm_put = 0;
else
/* DbC pm usage was put to 0, call get */
pm_runtime_get(dbc->dev);
break;
default:
break;
}
dbc->state_timestamp = jiffies;
dbc->state = new_state;
}
@@ -681,7 +706,7 @@ static int xhci_dbc_start(struct xhci_dbc *dbc)
WARN_ON(!dbc);
pm_runtime_get_sync(dbc->dev); /* note this was self.controller */
pm_runtime_get(dbc->dev);
spin_lock_irqsave(&dbc->lock, flags);
ret = xhci_do_dbc_start(dbc);
@@ -706,6 +731,7 @@ static int xhci_dbc_start(struct xhci_dbc *dbc)
static void xhci_dbc_stop(struct xhci_dbc *dbc)
{
unsigned long flags;
bool need_rpm_put = false;
WARN_ON(!dbc);
@@ -731,12 +757,20 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc)
spin_lock_irqsave(&dbc->lock, flags);
writel(0, &dbc->regs->control);
if (dbc->state == DS_CONNECTED || dbc->state == DS_CONFIGURED ||
dbc->pending_rpm_put)
need_rpm_put = true;
dbc->pending_rpm_put = 0;
xhci_dbc_set_state(dbc, DS_DISABLED);
spin_unlock_irqrestore(&dbc->lock, flags);
xhci_dbc_mem_cleanup(dbc);
pm_runtime_put(dbc->dev); /* note, was self.controller */
if (need_rpm_put)
pm_runtime_put(dbc->dev);
}
static void
@@ -908,6 +942,12 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
dev_info(dbc->dev, "DbC connected\n");
} else if (!(ctrl & DBC_CTRL_DBC_ENABLE)) {
dev_err(dbc->dev, "unexpected DbC disable, xHC reset?\n");
} else if (dbc->pending_rpm_put &&
time_is_before_jiffies(dbc->state_timestamp +
msecs_to_jiffies(DBC_AUTOSUSPEND_DELAY))) {
dbc->pending_rpm_put = 0;
dev_dbg(dbc->dev, "DbC Enabled state for 15 seconds, allow rpm suspend\n");
pm_runtime_put(dbc->dev);
}
return EVT_DONE;
@@ -1096,6 +1136,9 @@ static ssize_t dbc_show(struct device *dev,
if (dbc->state >= ARRAY_SIZE(dbc_state_strings))
return sysfs_emit(buf, "unknown\n");
if (dbc->resume_required)
return sysfs_emit(buf, "suspended\n");
return sysfs_emit(buf, "%s\n", dbc_state_strings[dbc->state]);
}
@@ -1110,12 +1153,25 @@ static ssize_t dbc_store(struct device *dev,
dbc = xhci->dbc;
if (sysfs_streq(buf, "enable")) {
pm_runtime_get_sync(dbc->dev);
mutex_lock(&dbc->enable_mutex);
/*
* DbC may already be enabled here if xhci was suspended with
* dbc->resume_required set, and resumed by pm_runtime_get_sync()
* above. In this case we end up calling xhci_dbc_start() twice,
* second time returns an error but is harmless
*/
xhci_dbc_start(dbc);
mutex_unlock(&dbc->enable_mutex);
pm_runtime_put(dbc->dev);
} else if (sysfs_streq(buf, "disable")) {
mutex_lock(&dbc->enable_mutex);
dbc->resume_required = 0;
xhci_dbc_stop(dbc);
mutex_unlock(&dbc->enable_mutex);
} else {
return -EINVAL;

View File

@@ -114,6 +114,8 @@ struct dbc_ep {
#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
#define DBC_XFER_INACTIVITY_TIMEOUT 10 /* milliseconds */
#define DBC_ENUMERATION_TIMEOUT 2000 /* milliseconds */
#define DBC_AUTOSUSPEND_DELAY 15000 /* milliseconds */
/*
* Private structure for DbC hardware state:
*/
@@ -166,6 +168,7 @@ struct xhci_dbc {
unsigned long xfer_timestamp;
unsigned long state_timestamp;
unsigned resume_required:1;
unsigned pending_rpm_put:1;
struct dbc_ep eps[2];
const struct dbc_driver *driver;

View File

@@ -58,6 +58,8 @@ xhci_ring_to_sgtable(struct xhci_sideband *sb, struct xhci_ring *ring)
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL))
goto err;
kvfree(pages);
/*
* Save first segment dma address to sg dma_address field for the sideband
* client to have access to the IOVA of the ring.

View File

@@ -3785,6 +3785,7 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_virt_device *vdev;
struct xhci_command *command;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_stream_info *stream_info[EP_CTX_PER_DEV];
unsigned int ep_index;
unsigned long flags;
u32 changed_ep_bitmask;
@@ -3845,10 +3846,15 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
if (ret < 0)
return ret;
/*
* dma_free_coherent() called by xhci_free_stream_info() may sleep,
* so save stream_info pointers and clear references under lock,
* then free the memory outside lock.
*/
spin_lock_irqsave(&xhci->lock, flags);
for (i = 0; i < num_eps; i++) {
ep_index = xhci_get_endpoint_index(&eps[i]->desc);
xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info);
stream_info[i] = vdev->eps[ep_index].stream_info;
vdev->eps[ep_index].stream_info = NULL;
/* FIXME Unset maxPstreams in endpoint context and
* update deq ptr to point to normal string ring.
@@ -3858,6 +3864,9 @@ static int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
}
spin_unlock_irqrestore(&xhci->lock, flags);
for (i = 0; i < num_eps; i++)
xhci_free_stream_info(xhci, stream_info[i]);
return 0;
}

View File

@@ -320,7 +320,6 @@ static int chaoskey_release(struct inode *inode, struct file *file)
mutex_unlock(&dev->lock);
destruction:
mutex_unlock(&chaoskey_list_lock);
usb_dbg(interface, "release success");
return rv;
}

View File

@@ -63,6 +63,7 @@ MODULE_DEVICE_TABLE(usb, idmouse_table);
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
struct kref kref;
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
@@ -209,8 +210,10 @@ static int idmouse_resume(struct usb_interface *intf)
return 0;
}
static inline void idmouse_delete(struct usb_idmouse *dev)
static inline void idmouse_delete(struct kref *kref)
{
struct usb_idmouse *dev = container_of(kref, struct usb_idmouse, kref);
kfree(dev->bulk_in_buffer);
kfree(dev);
}
@@ -254,6 +257,8 @@ static int idmouse_open(struct inode *inode, struct file *file)
/* increment our usage count for the driver */
++dev->open;
kref_get(&dev->kref);
/* save our object in the file's private structure */
file->private_data = dev;
@@ -277,16 +282,11 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* lock our device */
mutex_lock(&dev->lock);
--dev->open;
mutex_unlock(&dev->lock);
kref_put(&dev->kref, idmouse_delete);
if (!dev->present) {
/* the device was unplugged before the file was released */
mutex_unlock(&dev->lock);
idmouse_delete(dev);
} else {
mutex_unlock(&dev->lock);
}
return 0;
}
@@ -334,6 +334,7 @@ static int idmouse_probe(struct usb_interface *interface,
if (dev == NULL)
return -ENOMEM;
kref_init(&dev->kref);
mutex_init(&dev->lock);
dev->udev = udev;
dev->interface = interface;
@@ -342,8 +343,7 @@ static int idmouse_probe(struct usb_interface *interface,
result = usb_find_bulk_in_endpoint(iface_desc, &endpoint);
if (result) {
dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
idmouse_delete(dev);
return result;
goto err_put_kref;
}
dev->orig_bi_size = usb_endpoint_maxp(endpoint);
@@ -351,8 +351,8 @@ static int idmouse_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
idmouse_delete(dev);
return -ENOMEM;
result = -ENOMEM;
goto err_put_kref;
}
/* allow device read, write and ioctl */
@@ -364,14 +364,18 @@ static int idmouse_probe(struct usb_interface *interface,
if (result) {
/* something prevented us from registering this device */
dev_err(&interface->dev, "Unable to allocate minor number.\n");
idmouse_delete(dev);
return result;
goto err_put_kref;
}
/* be noisy */
dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC);
return 0;
err_put_kref:
kref_put(&dev->kref, idmouse_delete);
return result;
}
static void idmouse_disconnect(struct usb_interface *interface)
@@ -387,14 +391,9 @@ static void idmouse_disconnect(struct usb_interface *interface)
/* prevent device read, write and ioctl */
dev->present = 0;
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open) {
mutex_unlock(&dev->lock);
idmouse_delete(dev);
} else {
/* unlock */
mutex_unlock(&dev->lock);
}
mutex_unlock(&dev->lock);
kref_put(&dev->kref, idmouse_delete);
dev_info(&interface->dev, "disconnected\n");
}

View File

@@ -72,6 +72,7 @@ static struct usb_driver iowarrior_driver;
/* Structure to hold all of our device specific stuff */
struct iowarrior {
struct kref kref;
struct mutex mutex; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
@@ -240,8 +241,10 @@ static void iowarrior_write_callback(struct urb *urb)
/*
* iowarrior_delete
*/
static inline void iowarrior_delete(struct iowarrior *dev)
static inline void iowarrior_delete(struct kref *kref)
{
struct iowarrior *dev = container_of(kref, struct iowarrior, kref);
kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue);
@@ -637,6 +640,9 @@ static int iowarrior_open(struct inode *inode, struct file *file)
}
/* increment our usage count for the driver */
++dev->opened;
kref_get(&dev->kref);
/* save our object in the file's private structure */
file->private_data = dev;
retval = 0;
@@ -652,7 +658,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)
static int iowarrior_release(struct inode *inode, struct file *file)
{
struct iowarrior *dev;
int retval = 0;
dev = file->private_data;
if (!dev)
@@ -660,29 +665,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)
/* lock our device */
mutex_lock(&dev->mutex);
dev->opened = 0; /* we're closing now */
if (dev->opened <= 0) {
retval = -ENODEV; /* close called more than once */
mutex_unlock(&dev->mutex);
} else {
dev->opened = 0; /* we're closing now */
retval = 0;
if (dev->present) {
/*
The device is still connected so we only shutdown
pending read-/write-ops.
*/
usb_kill_urb(dev->int_in_urb);
wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait);
mutex_unlock(&dev->mutex);
} else {
/* The device was unplugged, cleanup resources */
mutex_unlock(&dev->mutex);
iowarrior_delete(dev);
}
if (dev->present) {
usb_kill_urb(dev->int_in_urb);
wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait);
}
return retval;
mutex_unlock(&dev->mutex);
kref_put(&dev->kref, iowarrior_delete);
return 0;
}
static __poll_t iowarrior_poll(struct file *file, poll_table * wait)
@@ -767,6 +761,7 @@ static int iowarrior_probe(struct usb_interface *interface,
if (!dev)
return retval;
kref_init(&dev->kref);
mutex_init(&dev->mutex);
atomic_set(&dev->intr_idx, 0);
@@ -885,7 +880,8 @@ static int iowarrior_probe(struct usb_interface *interface,
return retval;
error:
iowarrior_delete(dev);
kref_put(&dev->kref, iowarrior_delete);
return retval;
}
@@ -905,21 +901,18 @@ static void iowarrior_disconnect(struct usb_interface *interface)
/* prevent device read, write and ioctl */
dev->present = 0;
/* write urbs are not stopped on close() so kill unconditionally */
usb_kill_anchored_urbs(&dev->submitted);
if (dev->opened) {
/* There is a process that holds a filedescriptor to the device ,
so we only shutdown read-/write-ops going on.
Deleting the device is postponed until close() was called.
*/
usb_kill_urb(dev->int_in_urb);
usb_kill_anchored_urbs(&dev->submitted);
wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait);
mutex_unlock(&dev->mutex);
} else {
/* no process is using the device, cleanup now */
mutex_unlock(&dev->mutex);
iowarrior_delete(dev);
}
mutex_unlock(&dev->mutex);
kref_put(&dev->kref, iowarrior_delete);
}
/* usb specific object needed to register this driver with the usb subsystem */

View File

@@ -150,6 +150,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
/* Structure to hold all of our device specific stuff */
struct ld_usb {
struct kref kref;
struct mutex mutex; /* locks this structure */
struct usb_interface *intf; /* save off the usb interface pointer */
unsigned long disconnected:1;
@@ -201,8 +202,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
/*
* ld_usb_delete
*/
static void ld_usb_delete(struct ld_usb *dev)
static void ld_usb_delete(struct kref *kref)
{
struct ld_usb *dev = container_of(kref, struct ld_usb, kref);
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -355,6 +358,8 @@ static int ld_usb_open(struct inode *inode, struct file *file)
goto unlock_exit;
}
kref_get(&dev->kref);
/* save device in the file's private structure */
file->private_data = dev;
@@ -381,17 +386,8 @@ static int ld_usb_release(struct inode *inode, struct file *file)
mutex_lock(&dev->mutex);
if (dev->open_count != 1) {
retval = -ENODEV;
if (dev->disconnected)
goto unlock_exit;
}
if (dev->disconnected) {
/* the device was unplugged before the file was released */
mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
ld_usb_delete(dev);
goto exit;
}
/* wait until write transfer is finished */
if (dev->interrupt_out_busy)
@@ -401,7 +397,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
unlock_exit:
mutex_unlock(&dev->mutex);
kref_put(&dev->kref, ld_usb_delete);
exit:
return retval;
}
@@ -659,6 +655,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
dev = kzalloc_obj(*dev);
if (!dev)
goto exit;
kref_init(&dev->kref);
mutex_init(&dev->mutex);
spin_lock_init(&dev->rbsl);
dev->intf = intf;
@@ -740,7 +738,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
return retval;
error:
ld_usb_delete(dev);
kref_put(&dev->kref, ld_usb_delete);
return retval;
}
@@ -768,18 +766,18 @@ static void ld_usb_disconnect(struct usb_interface *intf)
mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
dev->disconnected = 1;
dev->disconnected = 1;
if (dev->open_count) {
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
mutex_unlock(&dev->mutex);
}
mutex_unlock(&dev->mutex);
kref_put(&dev->kref, ld_usb_delete);
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
(minor - USB_LD_MINOR_BASE));
}

View File

@@ -185,6 +185,7 @@ MODULE_DEVICE_TABLE(usb, tower_table);
/* Structure to hold all of our device specific stuff */
struct lego_usb_tower {
struct kref kref;
struct mutex lock; /* locks this structure */
struct usb_device *udev; /* save off the usb device pointer */
unsigned char minor; /* the starting minor number for this device */
@@ -220,7 +221,6 @@ struct lego_usb_tower {
/* local function prototypes */
static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
static inline void tower_delete(struct lego_usb_tower *dev);
static int tower_open(struct inode *inode, struct file *file);
static int tower_release(struct inode *inode, struct file *file);
static __poll_t tower_poll(struct file *file, poll_table *wait);
@@ -286,8 +286,10 @@ static inline void lego_usb_tower_debug_data(struct device *dev,
/*
* tower_delete
*/
static inline void tower_delete(struct lego_usb_tower *dev)
static inline void tower_delete(struct kref *kref)
{
struct lego_usb_tower *dev = container_of(kref, struct lego_usb_tower, kref);
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -381,6 +383,8 @@ static int tower_open(struct inode *inode, struct file *file)
dev->open_count = 1;
kref_get(&dev->kref);
unlock_exit:
mutex_unlock(&dev->lock);
@@ -404,14 +408,8 @@ static int tower_release(struct inode *inode, struct file *file)
mutex_lock(&dev->lock);
if (dev->disconnected) {
/* the device was unplugged before the file was released */
/* unlock here as tower_delete frees dev */
mutex_unlock(&dev->lock);
tower_delete(dev);
goto exit;
}
if (dev->disconnected)
goto out_unlock;
/* wait until write transfer is finished */
if (dev->interrupt_out_busy) {
@@ -425,7 +423,9 @@ static int tower_release(struct inode *inode, struct file *file)
dev->open_count = 0;
out_unlock:
mutex_unlock(&dev->lock);
kref_put(&dev->kref, tower_delete);
exit:
return retval;
}
@@ -752,6 +752,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_
if (!dev)
goto exit;
kref_init(&dev->kref);
mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
spin_lock_init(&dev->read_buffer_lock);
@@ -828,7 +829,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_
return retval;
error:
tower_delete(dev);
kref_put(&dev->kref, tower_delete);
return retval;
}
@@ -856,18 +857,18 @@ static void tower_disconnect(struct usb_interface *interface)
mutex_lock(&dev->lock);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
mutex_unlock(&dev->lock);
tower_delete(dev);
} else {
dev->disconnected = 1;
dev->disconnected = 1;
if (dev->open_count) {
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
mutex_unlock(&dev->lock);
}
mutex_unlock(&dev->lock);
kref_put(&dev->kref, tower_delete);
dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
(minor - LEGO_USB_TOWER_MINOR_BASE));
}

View File

@@ -344,6 +344,10 @@ int usbio_bulk_msg(struct auxiliary_device *adev, u8 type, u8 cmd, bool last,
if (ibuf_len < bpkt_len)
return -ENOSPC;
/* The device must not claim more payload than it actually sent. */
if (bpkt_len > act - sizeof(*bpkt))
return -EPROTO;
memcpy(ibuf, bpkt->data, bpkt_len);
return bpkt_len;
@@ -518,7 +522,7 @@ static int usbio_resume(struct usb_interface *intf)
static void usbio_disconnect(struct usb_interface *intf)
{
struct usbio_device *usbio = usb_get_intfdata(intf);
struct usbio_client *client;
struct usbio_client *client, *next;
/* Wakeup any clients waiting for a reply */
usbio->rxdat_len = 0;
@@ -535,7 +539,7 @@ static void usbio_disconnect(struct usb_interface *intf)
usb_kill_urb(usbio->urb);
usb_free_urb(usbio->urb);
list_for_each_entry_reverse(client, &usbio->cli_list, link) {
list_for_each_entry_safe_reverse(client, next, &usbio->cli_list, link) {
auxiliary_device_delete(&client->auxdev);
auxiliary_device_uninit(&client->auxdev);
}

View File

@@ -732,8 +732,11 @@ static int uss720_probe(struct usb_interface *intf,
* here. */
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
if (ret < 0)
if (ret < 0) {
priv->pp = NULL;
parport_del_port(pp);
goto probe_abort;
}
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {

View File

@@ -305,6 +305,7 @@ static int mtu3_gadget_queue(struct usb_ep *ep,
if (mtu3_prepare_transfer(mep)) {
ret = -EAGAIN;
usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
goto error;
}

View File

@@ -392,12 +392,14 @@ static int digi_write_oob_command(struct usb_serial_port *port,
len &= ~3;
memcpy(oob_port->write_urb->transfer_buffer, buf, len);
oob_port->write_urb->transfer_buffer_length = len;
ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
if (ret == 0) {
oob_priv->dp_write_urb_in_use = 1;
count -= len;
buf += len;
}
if (ret)
break;
oob_priv->dp_write_urb_in_use = 1;
count -= len;
buf += len;
}
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
if (ret)
@@ -427,20 +429,22 @@ static int digi_write_inb_command(struct usb_serial_port *port,
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long expire;
unsigned long flags;
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
if (timeout)
timeout += jiffies;
else
timeout = ULONG_MAX;
expire = jiffies + timeout;
spin_lock_irqsave(&priv->dp_port_lock, flags);
while (count > 0 && ret == 0) {
while (priv->dp_write_urb_in_use &&
time_before(jiffies, timeout)) {
while (priv->dp_write_urb_in_use) {
if (timeout && time_after(jiffies, expire)) {
ret = -ETIMEDOUT;
break;
}
cond_wait_interruptible_timeout_irqrestore(
&priv->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
@@ -449,6 +453,9 @@ static int digi_write_inb_command(struct usb_serial_port *port,
spin_lock_irqsave(&priv->dp_port_lock, flags);
}
if (ret)
break;
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
@@ -1069,6 +1076,7 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
int throttled;
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
@@ -1096,6 +1104,21 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
not_termios.c_iflag = ~tty->termios.c_iflag;
digi_set_termios(tty, port, &not_termios);
}
spin_lock_irq(&priv->dp_port_lock);
throttled = priv->dp_throttle_restart;
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
spin_unlock_irq(&priv->dp_port_lock);
if (throttled) {
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret) {
dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
return ret;
}
}
return 0;
}

View File

@@ -516,7 +516,7 @@ static int keyspan_pda_write_start(struct usb_serial_port *port)
if (count == room)
schedule_work(&priv->unthrottle_work);
return count;
return 0;
}
static void keyspan_pda_write_bulk_callback(struct urb *urb)

View File

@@ -1325,6 +1325,22 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x30), /* Telit FE990D50 (RNDIS) */
.driver_info = NCTRL(6) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x60) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x30), /* Telit FE990D50 (rmnet) */
.driver_info = NCTRL(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x60) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x30), /* Telit FE990D50 (MBIM) */
.driver_info = NCTRL(6) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x60) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x30), /* Telit FE990D50 (ECM) */
.driver_info = NCTRL(6) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x60) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1031, 0xff), /* Telit LE910C1-EUX */
.driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */

View File

@@ -2305,7 +2305,8 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
/*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready)))
if (unlikely(!(info->SD_Status & SD_Ready) &&
!(info->MS_Status & MS_Ready)))
result = ene_init(us);
if (result == USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;

View File

@@ -570,7 +570,7 @@ void usb_stor_adjust_quirks(struct usb_device *udev, u64 *fflags)
US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE |
US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES |
US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS |
US_FL_ALWAYS_SYNC);
US_FL_ALWAYS_SYNC | US_FL_NO_SAME);
p = quirks;
while (*p) {

View File

@@ -1537,7 +1537,9 @@ static int anx7411_i2c_probe(struct i2c_client *client)
if (anx7411_typec_check_connection(plat))
dev_err(dev, "check status\n");
pm_runtime_enable(dev);
ret = devm_pm_runtime_enable(dev);
if (ret)
goto free_wq;
return 0;

View File

@@ -1619,6 +1619,7 @@ static ssize_t select_usb_power_delivery_store(struct device *dev,
return -EINVAL;
ret = port->ops->pd_set(port, pd);
put_device(&pd->dev);
if (ret)
return ret;

View File

@@ -275,9 +275,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)
static void *typec_mux_match(const struct fwnode_handle *fwnode,
const char *id, void *data)
{
struct typec_mux_dev **mux_devs = data;
struct device *dev;
int i;
/*
* Device graph (OF graph) does not give any means to identify the
@@ -293,14 +291,6 @@ static void *typec_mux_match(const struct fwnode_handle *fwnode,
dev = class_find_device(&typec_mux_class, NULL, fwnode,
mux_fwnode_match);
/* Skip duplicates */
for (i = 0; i < TYPEC_MUX_MAX_DEVS; i++)
if (to_typec_mux_dev(dev) == mux_devs[i]) {
put_device(dev);
return NULL;
}
return dev ? to_typec_mux_dev(dev) : ERR_PTR(-EPROBE_DEFER);
}
@@ -326,8 +316,7 @@ struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode)
return ERR_PTR(-ENOMEM);
count = fwnode_connection_find_matches(fwnode, "mode-switch",
(void **)mux_devs,
typec_mux_match,
NULL, typec_mux_match,
(void **)mux_devs,
ARRAY_SIZE(mux_devs));
if (count <= 0) {

View File

@@ -206,12 +206,12 @@ static int ps883x_set(struct ps883x_retimer *retimer, struct typec_retimer_state
CONN_STATUS_1_DP_HPD_LEVEL;
switch (state->mode) {
case TYPEC_DP_STATE_D:
cfg0 |= CONN_STATUS_0_USB_3_1_CONNECTED;
fallthrough;
case TYPEC_DP_STATE_C:
cfg1 |= CONN_STATUS_1_DP_SINK_REQUESTED |
CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D;
fallthrough;
case TYPEC_DP_STATE_D:
cfg1 |= CONN_STATUS_0_USB_3_1_CONNECTED;
break;
default: /* MODE_E */
break;

View File

@@ -294,6 +294,8 @@ static int rt1711h_sw_reset(struct rt1711h_chip *chip)
return 0;
}
static void rt1711h_unregister_tcpci_port(void *tcpci);
static int rt1711h_probe(struct i2c_client *client)
{
int ret;
@@ -339,6 +341,10 @@ static int rt1711h_probe(struct i2c_client *client)
if (IS_ERR_OR_NULL(chip->tcpci))
return PTR_ERR(chip->tcpci);
ret = devm_add_action_or_reset(chip->dev, rt1711h_unregister_tcpci_port, chip->tcpci);
if (ret)
return ret;
ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
rt1711h_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
@@ -356,11 +362,9 @@ static int rt1711h_probe(struct i2c_client *client)
return 0;
}
static void rt1711h_remove(struct i2c_client *client)
static void rt1711h_unregister_tcpci_port(void *tcpci)
{
struct rt1711h_chip *chip = i2c_get_clientdata(client);
tcpci_unregister_port(chip->tcpci);
tcpci_unregister_port(tcpci);
}
static const struct rt1711h_chip_info rt1711h = {
@@ -393,7 +397,6 @@ static struct i2c_driver rt1711h_i2c_driver = {
.of_match_table = rt1711h_of_match,
},
.probe = rt1711h_probe,
.remove = rt1711h_remove,
.id_table = rt1711h_id,
};
module_i2c_driver(rt1711h_i2c_driver);

View File

@@ -2000,6 +2000,11 @@ static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt,
return;
}
if (pmdata->svid_index < 0 || pmdata->svid_index >= pmdata->nsvids) {
tcpm_log(port, "Invalid SVID index %d", pmdata->svid_index);
return;
}
for (i = 1; i < cnt; i++) {
if (pmdata->altmodes >= ALTMODE_DISCOVERY_MAX) {
/* Already logged in svdm_consume_svids() */
@@ -3088,7 +3093,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
if (svdm_version < 0)
return svdm_version;
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
@@ -3136,7 +3141,7 @@ static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_pl
if (svdm_version < 0)
return svdm_version;
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
header = VDO(altmode->svid, 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);

View File

@@ -166,12 +166,12 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp)
* that Multi-function is preferred.
*/
if (DP_CAP_CAPABILITY(cap) & DP_CAP_UFP_D) {
dp->data.status |= DP_STATUS_CON_UFP_D;
dp->data.status |= DP_STATUS_CON_DFP_D;
if (DP_CAP_UFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D))
dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC;
} else {
dp->data.status |= DP_STATUS_CON_DFP_D;
dp->data.status |= DP_STATUS_CON_UFP_D;
if (DP_CAP_DFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D))
dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC;
@@ -185,13 +185,12 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp)
static int ucsi_displayport_configure(struct ucsi_dp *dp)
{
u32 pins = DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
u64 command;
if (!dp->override)
return 0;
command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins);
command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, dp->data.conf);
return ucsi_send_command(dp->con->ucsi, command, NULL, 0);
}

View File

@@ -2017,6 +2017,26 @@ static void ucsi_resume_work(struct work_struct *work)
}
}
int ucsi_suspend(struct ucsi *ucsi)
{
int i;
/*
* Cancel pending work so it cannot access the firmware after the ACPI
* EC is stopped for suspend; state is re-read on resume.
*/
cancel_delayed_work_sync(&ucsi->work);
if (!ucsi->connector)
return 0;
for (i = 0; i < ucsi->cap.num_connectors; i++)
cancel_work_sync(&ucsi->connector[i].work);
return 0;
}
EXPORT_SYMBOL_GPL(ucsi_suspend);
int ucsi_resume(struct ucsi *ucsi)
{
if (ucsi->connector)

View File

@@ -582,6 +582,7 @@ int ucsi_write_message_out_command(struct ucsi *ucsi, u64 command,
void *msg_out, size_t msg_out_size);
void ucsi_altmode_update_active(struct ucsi_connector *con);
int ucsi_suspend(struct ucsi *ucsi);
int ucsi_resume(struct ucsi *ucsi);
void ucsi_notify_common(struct ucsi *ucsi, u32 cci);

View File

@@ -263,6 +263,13 @@ static void ucsi_acpi_remove(struct platform_device *pdev)
ucsi_acpi_notify);
}
static int ucsi_acpi_suspend(struct device *dev)
{
struct ucsi_acpi *ua = dev_get_drvdata(dev);
return ucsi_suspend(ua->ucsi);
}
static int ucsi_acpi_resume(struct device *dev)
{
struct ucsi_acpi *ua = dev_get_drvdata(dev);
@@ -270,7 +277,8 @@ static int ucsi_acpi_resume(struct device *dev)
return ucsi_resume(ua->ucsi);
}
static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, ucsi_acpi_suspend,
ucsi_acpi_resume);
static const struct acpi_device_id ucsi_acpi_match[] = {
{ "PNP0CA0", 0 },

View File

@@ -1521,8 +1521,8 @@ static void ucsi_ccg_remove(struct i2c_client *client)
cancel_work_sync(&uc->work);
pm_runtime_disable(uc->dev);
ucsi_unregister(uc->ucsi);
ucsi_destroy(uc->ucsi);
free_irq(uc->irq, uc);
ucsi_destroy(uc->ucsi);
}
static const struct of_device_id ucsi_ccg_of_match_table[] = {

View File

@@ -84,6 +84,8 @@ struct gaokun_ucsi_port {
struct auxiliary_device *bridge;
struct typec_mux *typec_mux;
struct typec_mux_state state;
struct typec_altmode dp_alt;
int idx;
enum gaokun_ucsi_ccx ccx;
@@ -292,24 +294,22 @@ static int gaokun_ucsi_refresh(struct gaokun_ucsi *uec)
static void gaokun_ucsi_handle_usb_mode(struct gaokun_ucsi_port *port)
{
struct gaokun_ucsi *uec = port->ucsi;
struct typec_mux_state state = {};
struct typec_altmode dp_alt = {};
int idx = port->idx, ret;
/*
* For every typec port on this platform, the only mode-switch is
* controlled by its qmp combo phy which consumes svid and mode only.
*/
dp_alt.svid = port->svid;
state.mode = port->mode;
state.alt = &dp_alt;
port->dp_alt.svid = port->svid;
port->state.mode = port->mode;
port->state.alt = &port->dp_alt;
if (idx >= uec->num_ports) {
dev_warn(uec->dev, "altmode port out of range: %d\n", idx);
return;
}
ret = typec_mux_set(port->typec_mux, &state);
ret = typec_mux_set(port->typec_mux, &port->state);
if (ret)
dev_err(uec->dev, "failed to set mux %d\n", ret);

View File

@@ -38,7 +38,6 @@ struct vep {
struct vrequest {
struct usb_request req;
struct vudc *udc;
struct list_head req_entry; /* Request queue */
};

View File

@@ -333,7 +333,6 @@ static int vep_queue(struct usb_ep *_ep, struct usb_request *_req,
static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct vep *ep;
struct vrequest *req;
struct vudc *udc;
struct vrequest *lst;
unsigned long flags;
@@ -343,8 +342,7 @@ static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return ret;
ep = to_vep(_ep);
req = to_vrequest(_req);
udc = req->udc;
udc = ep_to_vudc(ep);
if (!udc->driver)
return -ESHUTDOWN;

View File

@@ -29,6 +29,8 @@ static const struct speed_string speed_strings[] = {
{ USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
{ USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
{ USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
{ USB_SPEED_SUPER_PLUS, "10000", "Super Speed Plus(10000Mbps)" },
{ USB_SPEED_SUPER_PLUS, "20000", "Super Speed Plus(20000Mbps)" },
{ 0, NULL, NULL }
};

View File

@@ -57,6 +57,10 @@ static struct {
.speed = USB_SPEED_SUPER,
.name = "super-speed",
},
{
.speed = USB_SPEED_SUPER_PLUS,
.name = "super-speed-plus",
},
};
static

View File

@@ -338,6 +338,7 @@ int usbip_vhci_get_free_port(uint32_t speed)
switch (speed) {
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
if (vhci_driver->idev[i].hub != HUB_SPEED_SUPER)
continue;
break;