mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 14:30:06 -04: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:
@@ -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 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
},
|
||||
|
||||
@@ -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 @@ 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -732,8 +732,11 @@ static int uss720_probe(struct usb_interface *intf,
|
||||
* here. */
|
||||
ret = get_1284_register(pp, 0, ®, 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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, ¬_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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ struct vep {
|
||||
|
||||
struct vrequest {
|
||||
struct usb_request req;
|
||||
struct vudc *udc;
|
||||
struct list_head req_entry; /* Request queue */
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
|
||||
@@ -57,6 +57,10 @@ static struct {
|
||||
.speed = USB_SPEED_SUPER,
|
||||
.name = "super-speed",
|
||||
},
|
||||
{
|
||||
.speed = USB_SPEED_SUPER_PLUS,
|
||||
.name = "super-speed-plus",
|
||||
},
|
||||
};
|
||||
|
||||
static
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user