mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
commit
534f8f051e
53 files changed
+463
-205
No files matched your search
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 @@ err_fw_corrupted:
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -631,6 +631,8 @@ cleanup_rings:
|
||||
}
|
||||
}
|
||||
|
||||
cdnsp_free_stream_ctx(pdev, pep);
|
||||
|
||||
cleanup_stream_rings:
|
||||
kfree(pep->stream_info.stream_rings);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
},
|
||||
|
||||
+10
-13
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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++)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 @@ err_unlock:
|
||||
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;
|
||||
|
||||
Loaded 20 of 53 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user