mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
USB / Thunderbolt fixes for 6.2-rc5
Here are a number of small USB and Thunderbolt driver fixes and new device id changes for 6.2-rc5. Included in here are: - thunderbolt bugfixes for reported problems - new usb-serial driver ids added - onboard_hub usb driver fixes for much-reported problems - xhci bugfixes - typec bugfixes - ehci-fsl driver module alias fix - iowarrior header size fix - usb gadget driver fixes All of these, except for the iowarrior fix, have been in linux-next with no reported issues. The iowarrior fix passed the 0-day testing and is a one digit change based on a reported problem in the driver (which was written to a spec, not the real device that is now available.) Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY8wETA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymzQQCbBOPYVF6LWGoUCAi5nFbPgz0yAPYAoMpVH8Gx iSoT351gbn65LS+45ehc =mGTv -----END PGP SIGNATURE----- Merge tag 'usb-6.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt fixes from Greg KH: "Here are a number of small USB and Thunderbolt driver fixes and new device id changes for 6.2-rc5. Included in here are: - thunderbolt bugfixes for reported problems - new usb-serial driver ids added - onboard_hub usb driver fixes for much-reported problems - xhci bugfixes - typec bugfixes - ehci-fsl driver module alias fix - iowarrior header size fix - usb gadget driver fixes All of these, except for the iowarrior fix, have been in linux-next with no reported issues. The iowarrior fix passed the 0-day testing and is a one digit change based on a reported problem in the driver (which was written to a spec, not the real device that is now available)" * tag 'usb-6.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (40 commits) USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100 usb: host: ehci-fsl: Fix module alias usb: dwc3: fix extcon dependency usb: core: hub: disable autosuspend for TI TUSB8041 USB: fix misleading usb_set_intfdata() kernel doc usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate() USB: gadget: Add ID numbers to configfs-gadget driver names usb: typec: tcpm: Fix altmode re-registration causes sysfs create fail usb: gadget: g_webcam: Send color matching descriptor per frame usb: typec: altmodes/displayport: Use proper macro for pin assignment check usb: typec: altmodes/displayport: Fix pin assignment calculation usb: typec: altmodes/displayport: Add pin assignment helper usb: gadget: f_fs: Ensure ep0req is dequeued before free_request usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait usb: misc: onboard_hub: Move 'attach' work to the driver usb: misc: onboard_hub: Invert driver registration order usb: ucsi: Ensure connector delayed work items are flushed usb: musb: fix error return code in omap2430_probe() usb: chipidea: core: fix possible constant 0 if use IS_ERR(ci->role_switch) xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables ...
This commit is contained in:
commit
e67da28898
@ -427,13 +427,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
{
|
||||
u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
|
||||
int ret, i, last_idx = 0;
|
||||
struct usb4_port *usb4;
|
||||
|
||||
usb4 = port->usb4;
|
||||
if (!usb4)
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(&usb4->dev);
|
||||
|
||||
/*
|
||||
* Send broadcast RT to make sure retimer indices facing this
|
||||
@ -441,7 +434,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
*/
|
||||
ret = usb4_port_enumerate_retimers(port);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Enable sideband channel for each retimer. We can do this
|
||||
@ -471,12 +464,11 @@ int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!last_idx) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
if (!last_idx)
|
||||
return 0;
|
||||
|
||||
/* Add on-board retimers if they do not exist already */
|
||||
ret = 0;
|
||||
for (i = 1; i <= last_idx; i++) {
|
||||
struct tb_retimer *rt;
|
||||
|
||||
@ -490,10 +482,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(&usb4->dev);
|
||||
pm_runtime_put_autosuspend(&usb4->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -628,11 +628,15 @@ static void tb_scan_port(struct tb_port *port)
|
||||
* Downstream switch is reachable through two ports.
|
||||
* Only scan on the primary port (link_nr == 0).
|
||||
*/
|
||||
|
||||
if (port->usb4)
|
||||
pm_runtime_get_sync(&port->usb4->dev);
|
||||
|
||||
if (tb_wait_for_port(port, false) <= 0)
|
||||
return;
|
||||
goto out_rpm_put;
|
||||
if (port->remote) {
|
||||
tb_port_dbg(port, "port already has a remote\n");
|
||||
return;
|
||||
goto out_rpm_put;
|
||||
}
|
||||
|
||||
tb_retimer_scan(port, true);
|
||||
@ -647,12 +651,12 @@ static void tb_scan_port(struct tb_port *port)
|
||||
*/
|
||||
if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
|
||||
tb_scan_xdomain(port);
|
||||
return;
|
||||
goto out_rpm_put;
|
||||
}
|
||||
|
||||
if (tb_switch_configure(sw)) {
|
||||
tb_switch_put(sw);
|
||||
return;
|
||||
goto out_rpm_put;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -681,7 +685,7 @@ static void tb_scan_port(struct tb_port *port)
|
||||
|
||||
if (tb_switch_add(sw)) {
|
||||
tb_switch_put(sw);
|
||||
return;
|
||||
goto out_rpm_put;
|
||||
}
|
||||
|
||||
/* Link the switches using both links if available */
|
||||
@ -733,6 +737,12 @@ static void tb_scan_port(struct tb_port *port)
|
||||
|
||||
tb_add_dp_resources(sw);
|
||||
tb_scan_switch(sw);
|
||||
|
||||
out_rpm_put:
|
||||
if (port->usb4) {
|
||||
pm_runtime_mark_last_busy(&port->usb4->dev);
|
||||
pm_runtime_put_autosuspend(&port->usb4->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
|
||||
|
@ -1275,7 +1275,7 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel,
|
||||
return;
|
||||
} else if (!ret) {
|
||||
/* Use maximum link rate if the link valid is not set */
|
||||
ret = usb4_usb3_port_max_link_rate(tunnel->src_port);
|
||||
ret = tb_usb3_max_link_rate(tunnel->dst_port, tunnel->src_port);
|
||||
if (ret < 0) {
|
||||
tb_tunnel_warn(tunnel, "failed to read maximum link rate\n");
|
||||
return;
|
||||
|
@ -1419,12 +1419,19 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
|
||||
* registered, we notify the userspace that it has changed.
|
||||
*/
|
||||
if (!update) {
|
||||
struct tb_port *port;
|
||||
/*
|
||||
* Now disable lane 1 if bonding was not enabled. Do
|
||||
* this only if bonding was possible at the beginning
|
||||
* (that is we are the connection manager and there are
|
||||
* two lanes).
|
||||
*/
|
||||
if (xd->bonding_possible) {
|
||||
struct tb_port *port;
|
||||
|
||||
/* Now disable lane 1 if bonding was not enabled */
|
||||
port = tb_port_at(xd->route, tb_xdomain_parent(xd));
|
||||
if (!port->bonded)
|
||||
tb_port_disable(port->dual_link_port);
|
||||
port = tb_port_at(xd->route, tb_xdomain_parent(xd));
|
||||
if (!port->bonded)
|
||||
tb_port_disable(port->dual_link_port);
|
||||
}
|
||||
|
||||
if (device_add(&xd->dev)) {
|
||||
dev_err(&xd->dev, "failed to add XDomain device\n");
|
||||
|
@ -2614,6 +2614,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
u8 req_on_hw_ring = 0;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int val;
|
||||
|
||||
if (!ep || !request || !ep->desc)
|
||||
return -EINVAL;
|
||||
@ -2649,6 +2650,13 @@ found:
|
||||
|
||||
/* Update ring only if removed request is on pending_req_list list */
|
||||
if (req_on_hw_ring && link_trb) {
|
||||
/* Stop DMA */
|
||||
writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd);
|
||||
|
||||
/* wait for DFLUSH cleared */
|
||||
readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
|
||||
!(val & EP_CMD_DFLUSH), 1, 1000);
|
||||
|
||||
link_trb->buffer = cpu_to_le32(TRB_BUFFER(priv_ep->trb_pool_dma +
|
||||
((priv_req->end_trb + 1) * TRB_SIZE)));
|
||||
link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control) & TRB_CYCLE) |
|
||||
@ -2660,6 +2668,10 @@ found:
|
||||
|
||||
cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
|
||||
|
||||
req = cdns3_next_request(&priv_ep->pending_req_list);
|
||||
if (req)
|
||||
cdns3_rearm_transfer(priv_ep, 1);
|
||||
|
||||
not_found:
|
||||
spin_unlock_irqrestore(&priv_dev->lock, flags);
|
||||
return ret;
|
||||
|
@ -1294,12 +1294,12 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
|
||||
cable_id = &ci->platdata->id_extcon;
|
||||
cable_vbus = &ci->platdata->vbus_extcon;
|
||||
|
||||
if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch))
|
||||
if ((!IS_ERR(cable_id->edev) || ci->role_switch)
|
||||
&& ci->is_otg &&
|
||||
(otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
|
||||
ci_irq(ci);
|
||||
|
||||
if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch))
|
||||
if ((!IS_ERR(cable_vbus->edev) || ci->role_switch)
|
||||
&& ci->is_otg &&
|
||||
(otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
|
||||
ci_irq(ci);
|
||||
|
@ -44,6 +44,9 @@
|
||||
#define USB_PRODUCT_USB5534B 0x5534
|
||||
#define USB_VENDOR_CYPRESS 0x04b4
|
||||
#define USB_PRODUCT_CY7C65632 0x6570
|
||||
#define USB_VENDOR_TEXAS_INSTRUMENTS 0x0451
|
||||
#define USB_PRODUCT_TUSB8041_USB3 0x8140
|
||||
#define USB_PRODUCT_TUSB8041_USB2 0x8142
|
||||
#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
|
||||
#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
|
||||
|
||||
@ -5854,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = {
|
||||
.idVendor = USB_VENDOR_GENESYS_LOGIC,
|
||||
.bInterfaceClass = USB_CLASS_HUB,
|
||||
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
|
||||
| USB_DEVICE_ID_MATCH_PRODUCT,
|
||||
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
|
||||
.idProduct = USB_PRODUCT_TUSB8041_USB2,
|
||||
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
|
||||
| USB_DEVICE_ID_MATCH_PRODUCT,
|
||||
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
|
||||
.idProduct = USB_PRODUCT_TUSB8041_USB3,
|
||||
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
|
||||
.bDeviceClass = USB_CLASS_HUB},
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
|
||||
|
@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
|
||||
|
||||
#define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899"
|
||||
#define USB_DSM_DISABLE_U1_U2_FOR_PORT 5
|
||||
|
||||
/**
|
||||
* usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port.
|
||||
* @hdev: USB device belonging to the usb hub
|
||||
* @index: zero based port index
|
||||
*
|
||||
* Some USB3 ports may not support USB3 link power management U1/U2 states
|
||||
* due to different retimer setup. ACPI provides _DSM method which returns 0x01
|
||||
* if U1 and U2 states should be disabled. Evaluate _DSM with:
|
||||
* Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899
|
||||
* Arg1: Revision ID = 0
|
||||
* Arg2: Function Index = 5
|
||||
* Arg3: (empty)
|
||||
*
|
||||
* Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0
|
||||
*/
|
||||
|
||||
int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
acpi_handle port_handle;
|
||||
int port1 = index + 1;
|
||||
guid_t guid;
|
||||
int ret;
|
||||
|
||||
ret = guid_parse(UUID_USB_CONTROLLER_DSM, &guid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port_handle = usb_get_hub_port_acpi_handle(hdev, port1);
|
||||
if (!port_handle) {
|
||||
dev_dbg(&hdev->dev, "port-%d no acpi handle\n", port1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!acpi_check_dsm(port_handle, &guid, 0,
|
||||
BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) {
|
||||
dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n",
|
||||
port1, USB_DSM_DISABLE_U1_U2_FOR_PORT);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
obj = acpi_evaluate_dsm(port_handle, &guid, 0,
|
||||
USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
|
||||
|
||||
if (!obj)
|
||||
return -ENODEV;
|
||||
|
||||
if (obj->type != ACPI_TYPE_INTEGER) {
|
||||
dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
|
||||
ACPI_FREE(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->integer.value == 0x01)
|
||||
ret = 1;
|
||||
|
||||
ACPI_FREE(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable);
|
||||
|
||||
/**
|
||||
* usb_acpi_set_power_state - control usb port's power via acpi power
|
||||
* resource
|
||||
|
@ -3,6 +3,7 @@
|
||||
config USB_DWC3
|
||||
tristate "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB || USB_GADGET) && HAS_DMA
|
||||
depends on (EXTCON || EXTCON=n)
|
||||
select USB_XHCI_PLATFORM if USB_XHCI_HCD
|
||||
select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE
|
||||
help
|
||||
@ -44,7 +45,6 @@ config USB_DWC3_GADGET
|
||||
config USB_DWC3_DUAL_ROLE
|
||||
bool "Dual Role mode"
|
||||
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
|
||||
depends on (EXTCON=y || EXTCON=USB_DWC3)
|
||||
help
|
||||
This is the default mode of working of DWC3 controller where
|
||||
both host and gadget features are enabled.
|
||||
|
@ -393,6 +393,7 @@ static void gadget_info_attr_release(struct config_item *item)
|
||||
WARN_ON(!list_empty(&gi->string_list));
|
||||
WARN_ON(!list_empty(&gi->available_func));
|
||||
kfree(gi->composite.gadget_driver.function);
|
||||
kfree(gi->composite.gadget_driver.driver.name);
|
||||
kfree(gi);
|
||||
}
|
||||
|
||||
@ -1572,7 +1573,6 @@ static const struct usb_gadget_driver configfs_driver_template = {
|
||||
.max_speed = USB_SPEED_SUPER_PLUS,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "configfs-gadget",
|
||||
},
|
||||
.match_existing_only = 1,
|
||||
};
|
||||
@ -1623,13 +1623,21 @@ static struct config_group *gadgets_make(
|
||||
|
||||
gi->composite.gadget_driver = configfs_driver_template;
|
||||
|
||||
gi->composite.gadget_driver.driver.name = kasprintf(GFP_KERNEL,
|
||||
"configfs-gadget.%s", name);
|
||||
if (!gi->composite.gadget_driver.driver.name)
|
||||
goto err;
|
||||
|
||||
gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
|
||||
gi->composite.name = gi->composite.gadget_driver.function;
|
||||
|
||||
if (!gi->composite.gadget_driver.function)
|
||||
goto err;
|
||||
goto out_free_driver_name;
|
||||
|
||||
return &gi->group;
|
||||
|
||||
out_free_driver_name:
|
||||
kfree(gi->composite.gadget_driver.driver.name);
|
||||
err:
|
||||
kfree(gi);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -279,6 +279,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
|
||||
struct usb_request *req = ffs->ep0req;
|
||||
int ret;
|
||||
|
||||
if (!req)
|
||||
return -EINVAL;
|
||||
|
||||
req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
|
||||
|
||||
spin_unlock_irq(&ffs->ev.waitq.lock);
|
||||
@ -1892,10 +1895,14 @@ static void functionfs_unbind(struct ffs_data *ffs)
|
||||
ENTER();
|
||||
|
||||
if (!WARN_ON(!ffs->gadget)) {
|
||||
/* dequeue before freeing ep0req */
|
||||
usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
|
||||
mutex_lock(&ffs->mutex);
|
||||
usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
|
||||
ffs->ep0req = NULL;
|
||||
ffs->gadget = NULL;
|
||||
clear_bit(FFS_FL_BOUND, &ffs->flags);
|
||||
mutex_unlock(&ffs->mutex);
|
||||
ffs_data_put(ffs);
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
|
||||
/* peak (theoretical) bulk transfer rate in bits-per-second */
|
||||
static inline unsigned ncm_bitrate(struct usb_gadget *g)
|
||||
{
|
||||
if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
|
||||
if (!g)
|
||||
return 0;
|
||||
else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
|
||||
return 4250000000U;
|
||||
else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
|
||||
return 3750000000U;
|
||||
|
@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data)
|
||||
*/
|
||||
|
||||
static const char *CHIP;
|
||||
static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dev_data *dev;
|
||||
int rc;
|
||||
|
||||
if (the_device)
|
||||
return -ESRCH;
|
||||
mutex_lock(&sb_mutex);
|
||||
|
||||
if (the_device) {
|
||||
rc = -ESRCH;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
CHIP = usb_get_gadget_udc_name();
|
||||
if (!CHIP)
|
||||
return -ENODEV;
|
||||
if (!CHIP) {
|
||||
rc = -ENODEV;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* superblock */
|
||||
sb->s_blocksize = PAGE_SIZE;
|
||||
@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
|
||||
* from binding to a controller.
|
||||
*/
|
||||
the_device = dev;
|
||||
return 0;
|
||||
rc = 0;
|
||||
goto Done;
|
||||
|
||||
Enomem:
|
||||
Enomem:
|
||||
kfree(CHIP);
|
||||
CHIP = NULL;
|
||||
rc = -ENOMEM;
|
||||
|
||||
return -ENOMEM;
|
||||
Done:
|
||||
mutex_unlock(&sb_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* "mount -t gadgetfs path /dev/gadget" ends up here */
|
||||
@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc)
|
||||
static void
|
||||
gadgetfs_kill_sb (struct super_block *sb)
|
||||
{
|
||||
mutex_lock(&sb_mutex);
|
||||
kill_litter_super (sb);
|
||||
if (the_device) {
|
||||
put_dev (the_device);
|
||||
@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb)
|
||||
}
|
||||
kfree(CHIP);
|
||||
CHIP = NULL;
|
||||
mutex_unlock(&sb_mutex);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -293,6 +293,7 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
@ -305,6 +306,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
@ -317,6 +319,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "ehci-fsl.h"
|
||||
|
||||
#define DRIVER_DESC "Freescale EHCI Host controller driver"
|
||||
#define DRV_NAME "ehci-fsl"
|
||||
#define DRV_NAME "fsl-ehci"
|
||||
|
||||
static struct hc_driver __read_mostly fsl_ehci_hc_driver;
|
||||
|
||||
|
@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd";
|
||||
static struct hc_driver __read_mostly xhci_pci_hc_driver;
|
||||
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd);
|
||||
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
|
||||
static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
|
||||
.reset = xhci_pci_setup,
|
||||
.update_hub_device = xhci_pci_update_hub_device,
|
||||
};
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
@ -352,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
|
||||
NULL);
|
||||
ACPI_FREE(obj);
|
||||
}
|
||||
|
||||
static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_hub *rhub = &xhci->usb3_rhub;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* This is not the usb3 roothub we are looking for */
|
||||
if (hcd != rhub->hcd)
|
||||
return;
|
||||
|
||||
if (hdev->maxchild > rhub->num_ports) {
|
||||
dev_err(&hdev->dev, "USB3 roothub port number mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdev->maxchild; i++) {
|
||||
ret = usb_acpi_port_lpm_incapable(hdev, i);
|
||||
|
||||
dev_dbg(&hdev->dev, "port-%d disable U1/U2 _DSM: %d\n", i + 1, ret);
|
||||
|
||||
if (ret >= 0) {
|
||||
rhub->ports[i]->lpm_incapable = ret;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
|
||||
static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) { }
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
@ -386,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
return xhci_pci_reinit(xhci, pdev);
|
||||
}
|
||||
|
||||
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags)
|
||||
{
|
||||
/* Check if acpi claims some USB3 roothub ports are lpm incapable */
|
||||
if (!hdev->parent)
|
||||
xhci_find_lpm_incapable_ports(hcd, hdev);
|
||||
|
||||
return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to register our own PCI probe function (instead of the USB core's
|
||||
* function) in order to create a second roothub under xHCI.
|
||||
@ -455,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
|
||||
pm_runtime_allow(&dev->dev);
|
||||
|
||||
dma_set_max_seg_size(&dev->dev, UINT_MAX);
|
||||
|
||||
return 0;
|
||||
|
||||
put_usb3_hcd:
|
||||
|
@ -1169,7 +1169,10 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_ep *ep;
|
||||
struct xhci_ring *ring;
|
||||
|
||||
ep = &xhci->devs[slot_id]->eps[ep_index];
|
||||
ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
|
||||
if (!ep)
|
||||
return;
|
||||
|
||||
if ((ep->ep_state & EP_HAS_STREAMS) ||
|
||||
(ep->ep_state & EP_GETTING_NO_STREAMS)) {
|
||||
int stream_id;
|
||||
|
@ -3974,6 +3974,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
unsigned long flags;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
@ -4000,7 +4001,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
|
||||
virt_dev->udev = NULL;
|
||||
xhci_disable_slot(xhci, udev->slot_id);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
}
|
||||
|
||||
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
|
||||
@ -5044,6 +5049,7 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
struct usb_device *udev, enum usb3_link_state state)
|
||||
{
|
||||
struct xhci_hcd *xhci;
|
||||
struct xhci_port *port;
|
||||
u16 hub_encoded_timeout;
|
||||
int mel;
|
||||
int ret;
|
||||
@ -5060,6 +5066,13 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
if (xhci_check_tier_policy(xhci, udev, state) < 0)
|
||||
return USB3_LPM_DISABLED;
|
||||
|
||||
/* If connected to root port then check port can handle lpm */
|
||||
if (udev->parent && !udev->parent->parent) {
|
||||
port = xhci->usb3_rhub.ports[udev->portnum - 1];
|
||||
if (port->lpm_incapable)
|
||||
return USB3_LPM_DISABLED;
|
||||
}
|
||||
|
||||
hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
|
||||
mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
|
||||
if (mel < 0) {
|
||||
@ -5119,7 +5132,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
|
||||
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
|
||||
* internal data structures for the device.
|
||||
*/
|
||||
static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
@ -5219,6 +5232,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
xhci_free_command(xhci, config_cmd);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_update_hub_device);
|
||||
|
||||
static int xhci_get_frame(struct usb_hcd *hcd)
|
||||
{
|
||||
@ -5502,6 +5516,8 @@ void xhci_init_driver(struct hc_driver *drv,
|
||||
drv->check_bandwidth = over->check_bandwidth;
|
||||
if (over->reset_bandwidth)
|
||||
drv->reset_bandwidth = over->reset_bandwidth;
|
||||
if (over->update_hub_device)
|
||||
drv->update_hub_device = over->update_hub_device;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xhci_init_driver);
|
||||
|
@ -1735,6 +1735,7 @@ struct xhci_port {
|
||||
int hcd_portnum;
|
||||
struct xhci_hub *rhub;
|
||||
struct xhci_port_cap *port_cap;
|
||||
unsigned int lpm_incapable:1;
|
||||
};
|
||||
|
||||
struct xhci_hub {
|
||||
@ -1943,6 +1944,8 @@ struct xhci_driver_overrides {
|
||||
struct usb_host_endpoint *ep);
|
||||
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
|
||||
int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
};
|
||||
|
||||
#define XHCI_CFC_DELAY 10
|
||||
@ -2122,6 +2125,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep);
|
||||
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
|
||||
int xhci_ext_cap_init(struct xhci_hcd *xhci);
|
||||
|
||||
|
@ -814,7 +814,7 @@ static int iowarrior_probe(struct usb_interface *interface,
|
||||
break;
|
||||
|
||||
case USB_DEVICE_ID_CODEMERCS_IOW100:
|
||||
dev->report_size = 13;
|
||||
dev->report_size = 12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,10 @@
|
||||
|
||||
#include "onboard_usb_hub.h"
|
||||
|
||||
static void onboard_hub_attach_usb_driver(struct work_struct *work);
|
||||
|
||||
static struct usb_device_driver onboard_hub_usbdev_driver;
|
||||
static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver);
|
||||
|
||||
/************************** Platform driver **************************/
|
||||
|
||||
@ -45,7 +48,6 @@ struct onboard_hub {
|
||||
bool is_powered_on;
|
||||
bool going_away;
|
||||
struct list_head udev_list;
|
||||
struct work_struct attach_usb_driver_work;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
@ -271,8 +273,7 @@ static int onboard_hub_probe(struct platform_device *pdev)
|
||||
* This needs to be done deferred to avoid self-deadlocks on systems
|
||||
* with nested onboard hubs.
|
||||
*/
|
||||
INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver);
|
||||
schedule_work(&hub->attach_usb_driver_work);
|
||||
schedule_work(&attach_usb_driver_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -285,9 +286,6 @@ static int onboard_hub_remove(struct platform_device *pdev)
|
||||
|
||||
hub->going_away = true;
|
||||
|
||||
if (&hub->attach_usb_driver_work != current_work())
|
||||
cancel_work_sync(&hub->attach_usb_driver_work);
|
||||
|
||||
mutex_lock(&hub->lock);
|
||||
|
||||
/* unbind the USB devices to avoid dangling references to this device */
|
||||
@ -433,13 +431,13 @@ static int __init onboard_hub_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&onboard_hub_driver);
|
||||
ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
|
||||
ret = platform_driver_register(&onboard_hub_driver);
|
||||
if (ret)
|
||||
platform_driver_unregister(&onboard_hub_driver);
|
||||
usb_deregister_device_driver(&onboard_hub_usbdev_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -449,6 +447,8 @@ static void __exit onboard_hub_exit(void)
|
||||
{
|
||||
usb_deregister_device_driver(&onboard_hub_usbdev_driver);
|
||||
platform_driver_unregister(&onboard_hub_driver);
|
||||
|
||||
cancel_work_sync(&attach_usb_driver_work);
|
||||
}
|
||||
module_exit(onboard_hub_exit);
|
||||
|
||||
|
@ -411,8 +411,10 @@ static int omap2430_probe(struct platform_device *pdev)
|
||||
memset(musb_res, 0, sizeof(*musb_res) * ARRAY_SIZE(musb_res));
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
if (!res) {
|
||||
ret = -EINVAL;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
musb_res[i].start = res->start;
|
||||
musb_res[i].end = res->end;
|
||||
|
@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
|
||||
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
|
||||
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
|
||||
{ USB_DEVICE(0x0908, 0x0070) }, /* Siemens SCALANCE LPE-9000 USB Serial Console */
|
||||
{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
|
||||
{ USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
|
||||
{ USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
|
||||
|
@ -255,10 +255,16 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_PRODUCT_EP06 0x0306
|
||||
#define QUECTEL_PRODUCT_EM05G 0x030a
|
||||
#define QUECTEL_PRODUCT_EM060K 0x030b
|
||||
#define QUECTEL_PRODUCT_EM05G_CS 0x030c
|
||||
#define QUECTEL_PRODUCT_EM05CN_SG 0x0310
|
||||
#define QUECTEL_PRODUCT_EM05G_SG 0x0311
|
||||
#define QUECTEL_PRODUCT_EM05CN 0x0312
|
||||
#define QUECTEL_PRODUCT_EM05G_GR 0x0313
|
||||
#define QUECTEL_PRODUCT_EM05G_RS 0x0314
|
||||
#define QUECTEL_PRODUCT_EM12 0x0512
|
||||
#define QUECTEL_PRODUCT_RM500Q 0x0800
|
||||
#define QUECTEL_PRODUCT_RM520N 0x0801
|
||||
#define QUECTEL_PRODUCT_EC200U 0x0901
|
||||
#define QUECTEL_PRODUCT_EC200S_CN 0x6002
|
||||
#define QUECTEL_PRODUCT_EC200T 0x6026
|
||||
#define QUECTEL_PRODUCT_RM500K 0x7001
|
||||
@ -1159,8 +1165,18 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
|
||||
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN_SG, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_CS, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_GR, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_RS, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff),
|
||||
.driver_info = RSVD(6) | ZLP },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
|
||||
@ -1180,6 +1196,7 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },
|
||||
|
@ -116,6 +116,19 @@ static int uas_use_uas_driver(struct usb_interface *intf,
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2)
|
||||
flags |= US_FL_NO_ATA_1X;
|
||||
|
||||
/*
|
||||
* RTL9210-based enclosure from HIKSEMI, MD202 reportedly have issues
|
||||
* with UAS. This isn't distinguishable with just idVendor and
|
||||
* idProduct, use manufacturer and product too.
|
||||
*
|
||||
* Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
|
||||
*/
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bda &&
|
||||
le16_to_cpu(udev->descriptor.idProduct) == 0x9210 &&
|
||||
(udev->manufacturer && !strcmp(udev->manufacturer, "HIKSEMI")) &&
|
||||
(udev->product && !strcmp(udev->product, "MD202")))
|
||||
flags |= US_FL_IGNORE_UAS;
|
||||
|
||||
usb_stor_adjust_quirks(udev, &flags);
|
||||
|
||||
if (flags & US_FL_IGNORE_UAS) {
|
||||
|
@ -83,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_LUNS),
|
||||
|
||||
/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
|
||||
UNUSUAL_DEV(0x0bda, 0x9210, 0x0000, 0x9999,
|
||||
"Hiksemi",
|
||||
"External HDD",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_UAS),
|
||||
|
||||
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
|
||||
UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
|
||||
"Initio Corporation",
|
||||
|
@ -419,6 +419,18 @@ static const char * const pin_assignments[] = {
|
||||
[DP_PIN_ASSIGN_F] = "F",
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper function to extract a peripheral's currently supported
|
||||
* Pin Assignments from its DisplayPort alternate mode state.
|
||||
*/
|
||||
static u8 get_current_pin_assignments(struct dp_altmode *dp)
|
||||
{
|
||||
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D)
|
||||
return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo);
|
||||
else
|
||||
return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
pin_assignment_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
@ -445,10 +457,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
|
||||
assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
|
||||
else
|
||||
assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
|
||||
assignments = get_current_pin_assignments(dp);
|
||||
|
||||
if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
|
||||
ret = -EINVAL;
|
||||
@ -485,10 +494,7 @@ static ssize_t pin_assignment_show(struct device *dev,
|
||||
|
||||
cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
|
||||
|
||||
if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
|
||||
assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
|
||||
else
|
||||
assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
|
||||
assignments = get_current_pin_assignments(dp);
|
||||
|
||||
for (i = 0; assignments; assignments >>= 1, i++) {
|
||||
if (assignments & 1) {
|
||||
|
@ -4594,14 +4594,13 @@ static void run_state_machine(struct tcpm_port *port)
|
||||
tcpm_set_state(port, ready_state(port), 0);
|
||||
break;
|
||||
case DR_SWAP_CHANGE_DR:
|
||||
if (port->data_role == TYPEC_HOST) {
|
||||
tcpm_unregister_altmodes(port);
|
||||
tcpm_unregister_altmodes(port);
|
||||
if (port->data_role == TYPEC_HOST)
|
||||
tcpm_set_roles(port, true, port->pwr_role,
|
||||
TYPEC_DEVICE);
|
||||
} else {
|
||||
else
|
||||
tcpm_set_roles(port, true, port->pwr_role,
|
||||
TYPEC_HOST);
|
||||
}
|
||||
tcpm_ams_finish(port);
|
||||
tcpm_set_state(port, ready_state(port), 0);
|
||||
break;
|
||||
|
@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(ucsi_send_command);
|
||||
|
||||
struct ucsi_work {
|
||||
struct delayed_work work;
|
||||
struct list_head node;
|
||||
unsigned long delay;
|
||||
unsigned int count;
|
||||
struct ucsi_connector *con;
|
||||
@ -202,6 +203,7 @@ static void ucsi_poll_worker(struct work_struct *work)
|
||||
mutex_lock(&con->lock);
|
||||
|
||||
if (!con->partner) {
|
||||
list_del(&uwork->node);
|
||||
mutex_unlock(&con->lock);
|
||||
kfree(uwork);
|
||||
return;
|
||||
@ -209,10 +211,12 @@ static void ucsi_poll_worker(struct work_struct *work)
|
||||
|
||||
ret = uwork->cb(con);
|
||||
|
||||
if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT))
|
||||
if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) {
|
||||
queue_delayed_work(con->wq, &uwork->work, uwork->delay);
|
||||
else
|
||||
} else {
|
||||
list_del(&uwork->node);
|
||||
kfree(uwork);
|
||||
}
|
||||
|
||||
mutex_unlock(&con->lock);
|
||||
}
|
||||
@ -236,6 +240,7 @@ static int ucsi_partner_task(struct ucsi_connector *con,
|
||||
uwork->con = con;
|
||||
uwork->cb = cb;
|
||||
|
||||
list_add_tail(&uwork->node, &con->partner_tasks);
|
||||
queue_delayed_work(con->wq, &uwork->work, delay);
|
||||
|
||||
return 0;
|
||||
@ -1056,6 +1061,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
|
||||
INIT_WORK(&con->work, ucsi_handle_connector_change);
|
||||
init_completion(&con->complete);
|
||||
mutex_init(&con->lock);
|
||||
INIT_LIST_HEAD(&con->partner_tasks);
|
||||
con->num = index + 1;
|
||||
con->ucsi = ucsi;
|
||||
|
||||
@ -1420,8 +1426,20 @@ void ucsi_unregister(struct ucsi *ucsi)
|
||||
ucsi_unregister_altmodes(&ucsi->connector[i],
|
||||
UCSI_RECIPIENT_CON);
|
||||
ucsi_unregister_port_psy(&ucsi->connector[i]);
|
||||
if (ucsi->connector[i].wq)
|
||||
|
||||
if (ucsi->connector[i].wq) {
|
||||
struct ucsi_work *uwork;
|
||||
|
||||
mutex_lock(&ucsi->connector[i].lock);
|
||||
/*
|
||||
* queue delayed items immediately so they can execute
|
||||
* and free themselves before the wq is destroyed
|
||||
*/
|
||||
list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
|
||||
mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
|
||||
mutex_unlock(&ucsi->connector[i].lock);
|
||||
destroy_workqueue(ucsi->connector[i].wq);
|
||||
}
|
||||
typec_unregister_port(ucsi->connector[i].port);
|
||||
}
|
||||
|
||||
|
@ -322,6 +322,7 @@ struct ucsi_connector {
|
||||
struct work_struct work;
|
||||
struct completion complete;
|
||||
struct workqueue_struct *wq;
|
||||
struct list_head partner_tasks;
|
||||
|
||||
struct typec_port *port;
|
||||
struct typec_partner *partner;
|
||||
|
@ -267,16 +267,15 @@ static inline void *usb_get_intfdata(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_set_intfdata() - associate driver-specific data with the interface
|
||||
* @intf: the usb interface
|
||||
* @data: pointer to the device priv structure or %NULL
|
||||
* usb_set_intfdata() - associate driver-specific data with an interface
|
||||
* @intf: USB interface
|
||||
* @data: driver data
|
||||
*
|
||||
* Drivers should use this function in their probe() to associate their
|
||||
* driver-specific data with the usb interface.
|
||||
* Drivers can use this function in their probe() callbacks to associate
|
||||
* driver-specific data with an interface.
|
||||
*
|
||||
* When disconnecting, the core will take care of setting @intf back to %NULL,
|
||||
* so no actions are needed on the driver side. The interface should not be set
|
||||
* to %NULL before all actions completed (e.g. no outsanding URB remaining).
|
||||
* Note that there is generally no need to clear the driver-data pointer even
|
||||
* if some drivers do so for historical or implementation-specific reasons.
|
||||
*/
|
||||
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
|
||||
{
|
||||
@ -774,11 +773,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
|
||||
extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
|
||||
bool enable);
|
||||
extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
|
||||
extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index);
|
||||
#else
|
||||
static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
|
||||
bool enable) { return 0; }
|
||||
static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
|
||||
{ return true; }
|
||||
static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
/* USB autosuspend and autoresume */
|
||||
|
Loading…
Reference in New Issue
Block a user