mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
USB/Thunderbolt Fixes for 6.4-rc7
Here are some small USB and Thunderbolt driver fixes and new device ids for 6.4-rc7 to resolve some reported problems. Included in here are: - new USB serial device ids - USB gadget core fixes for long-dissussed problems - dwc3 bugfixes for reported issues. - typec driver fixes - thunderbolt driver fixes All of these have been in linux-next this week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZI24Fg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yn5SwCglLVWTIiXF+UXoocktinhvroZpp0AoJIy+z6B bhGaS1jqKZQMu88swuPZ =dSdQ -----END PGP SIGNATURE----- Merge tag 'usb-6.4-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt fixes from Greg KH: "Here are some small USB and Thunderbolt driver fixes and new device ids for 6.4-rc7 to resolve some reported problems. Included in here are: - new USB serial device ids - USB gadget core fixes for long-dissussed problems - dwc3 bugfixes for reported issues. - typec driver fixes - thunderbolt driver fixes All of these have been in linux-next this week with no reported issues" * tag 'usb-6.4-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: gadget: udc: core: Prevent soft_connect_store() race usb: gadget: udc: core: Offload usb_udc_vbus_handler processing usb: typec: Fix fast_role_swap_current show function usb: typec: ucsi: Fix command cancellation USB: dwc3: fix use-after-free on core driver unbind USB: dwc3: qcom: fix NULL-deref on suspend usb: dwc3: gadget: Reset num TRBs before giving back the request usb: gadget: udc: renesas_usb3: Fix RZ/V2M {modprobe,bind} error USB: serial: option: add Quectel EM061KGL series thunderbolt: Mask ring interrupt on Intel hardware as well thunderbolt: Do not touch CL state configuration during discovery thunderbolt: Increase DisplayPort Connection Manager handshake timeout thunderbolt: dma_test: Use correct value for absent rings when creating paths
This commit is contained in:
commit
670062e7e4
@ -192,9 +192,9 @@ static int dma_test_start_rings(struct dma_test *dt)
|
||||
}
|
||||
|
||||
ret = tb_xdomain_enable_paths(dt->xd, dt->tx_hopid,
|
||||
dt->tx_ring ? dt->tx_ring->hop : 0,
|
||||
dt->tx_ring ? dt->tx_ring->hop : -1,
|
||||
dt->rx_hopid,
|
||||
dt->rx_ring ? dt->rx_ring->hop : 0);
|
||||
dt->rx_ring ? dt->rx_ring->hop : -1);
|
||||
if (ret) {
|
||||
dma_test_free_rings(dt);
|
||||
return ret;
|
||||
@ -218,9 +218,9 @@ static void dma_test_stop_rings(struct dma_test *dt)
|
||||
tb_ring_stop(dt->tx_ring);
|
||||
|
||||
ret = tb_xdomain_disable_paths(dt->xd, dt->tx_hopid,
|
||||
dt->tx_ring ? dt->tx_ring->hop : 0,
|
||||
dt->tx_ring ? dt->tx_ring->hop : -1,
|
||||
dt->rx_hopid,
|
||||
dt->rx_ring ? dt->rx_ring->hop : 0);
|
||||
dt->rx_ring ? dt->rx_ring->hop : -1);
|
||||
if (ret)
|
||||
dev_warn(&dt->svc->dev, "failed to disable DMA paths\n");
|
||||
|
||||
|
@ -56,9 +56,14 @@ static int ring_interrupt_index(const struct tb_ring *ring)
|
||||
|
||||
static void nhi_mask_interrupt(struct tb_nhi *nhi, int mask, int ring)
|
||||
{
|
||||
if (nhi->quirks & QUIRK_AUTO_CLEAR_INT)
|
||||
return;
|
||||
iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
|
||||
if (nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
|
||||
u32 val;
|
||||
|
||||
val = ioread32(nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
|
||||
iowrite32(val & ~mask, nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
|
||||
} else {
|
||||
iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
|
||||
}
|
||||
}
|
||||
|
||||
static void nhi_clear_interrupt(struct tb_nhi *nhi, int ring)
|
||||
|
@ -737,6 +737,7 @@ static void tb_scan_port(struct tb_port *port)
|
||||
{
|
||||
struct tb_cm *tcm = tb_priv(port->sw->tb);
|
||||
struct tb_port *upstream_port;
|
||||
bool discovery = false;
|
||||
struct tb_switch *sw;
|
||||
int ret;
|
||||
|
||||
@ -804,8 +805,10 @@ static void tb_scan_port(struct tb_port *port)
|
||||
* tunnels and know which switches were authorized already by
|
||||
* the boot firmware.
|
||||
*/
|
||||
if (!tcm->hotplug_active)
|
||||
if (!tcm->hotplug_active) {
|
||||
dev_set_uevent_suppress(&sw->dev, true);
|
||||
discovery = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* At the moment Thunderbolt 2 and beyond (devices with LC) we
|
||||
@ -835,10 +838,14 @@ static void tb_scan_port(struct tb_port *port)
|
||||
* CL0s and CL1 are enabled and supported together.
|
||||
* Silently ignore CLx enabling in case CLx is not supported.
|
||||
*/
|
||||
ret = tb_switch_enable_clx(sw, TB_CL1);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
tb_sw_warn(sw, "failed to enable %s on upstream port\n",
|
||||
tb_switch_clx_name(TB_CL1));
|
||||
if (discovery) {
|
||||
tb_sw_dbg(sw, "discovery, not touching CL states\n");
|
||||
} else {
|
||||
ret = tb_switch_enable_clx(sw, TB_CL1);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
tb_sw_warn(sw, "failed to enable %s on upstream port\n",
|
||||
tb_switch_clx_name(TB_CL1));
|
||||
}
|
||||
|
||||
if (tb_switch_is_clx_enabled(sw, TB_CL1))
|
||||
/*
|
||||
|
@ -526,7 +526,7 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
|
||||
* Perform connection manager handshake between IN and OUT ports
|
||||
* before capabilities exchange can take place.
|
||||
*/
|
||||
ret = tb_dp_cm_handshake(in, out, 1500);
|
||||
ret = tb_dp_cm_handshake(in, out, 3000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1929,6 +1929,11 @@ static int dwc3_remove(struct platform_device *pdev)
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
/*
|
||||
* HACK: Clear the driver data, which is currently accessed by parent
|
||||
* glue drivers, before allowing the parent to suspend.
|
||||
*/
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
@ -308,7 +308,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
|
||||
/* Only usable in contexts where the role can not change. */
|
||||
static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
|
||||
{
|
||||
struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
|
||||
struct dwc3 *dwc;
|
||||
|
||||
/*
|
||||
* FIXME: Fix this layering violation.
|
||||
*/
|
||||
dwc = platform_get_drvdata(qcom->dwc3);
|
||||
|
||||
/* Core driver may not have probed yet. */
|
||||
if (!dwc)
|
||||
return false;
|
||||
|
||||
return dwc->xhci;
|
||||
}
|
||||
|
@ -198,6 +198,7 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
|
||||
list_del(&req->list);
|
||||
req->remaining = 0;
|
||||
req->needs_extra_trb = false;
|
||||
req->num_trbs = 0;
|
||||
|
||||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
|
@ -37,6 +37,14 @@ static const struct bus_type gadget_bus_type;
|
||||
* @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
|
||||
* @started: the UDC's started state. True if the UDC had started.
|
||||
* @allow_connect: Indicates whether UDC is allowed to be pulled up.
|
||||
* Set/cleared by gadget_(un)bind_driver() after gadget driver is bound or
|
||||
* unbound.
|
||||
* @connect_lock: protects udc->started, gadget->connect,
|
||||
* gadget->allow_connect and gadget->deactivate. The routines
|
||||
* usb_gadget_connect_locked(), usb_gadget_disconnect_locked(),
|
||||
* usb_udc_connect_control_locked(), usb_gadget_udc_start_locked() and
|
||||
* usb_gadget_udc_stop_locked() are called with this lock held.
|
||||
*
|
||||
* This represents the internal data structure which is used by the UDC-class
|
||||
* to hold information about udc driver and gadget together.
|
||||
@ -48,6 +56,9 @@ struct usb_udc {
|
||||
struct list_head list;
|
||||
bool vbus;
|
||||
bool started;
|
||||
bool allow_connect;
|
||||
struct work_struct vbus_work;
|
||||
struct mutex connect_lock;
|
||||
};
|
||||
|
||||
static struct class *udc_class;
|
||||
@ -687,17 +698,8 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
|
||||
|
||||
/**
|
||||
* usb_gadget_connect - software-controlled connect to USB host
|
||||
* @gadget:the peripheral being connected
|
||||
*
|
||||
* Enables the D+ (or potentially D-) pullup. The host will start
|
||||
* enumerating this gadget when the pullup is active and a VBUS session
|
||||
* is active (the link is powered).
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
static int usb_gadget_connect_locked(struct usb_gadget *gadget)
|
||||
__must_hold(&gadget->udc->connect_lock)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -706,10 +708,12 @@ int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gadget->deactivated) {
|
||||
if (gadget->deactivated || !gadget->udc->allow_connect || !gadget->udc->started) {
|
||||
/*
|
||||
* If gadget is deactivated we only save new state.
|
||||
* Gadget will be connected automatically after activation.
|
||||
* If the gadget isn't usable (because it is deactivated,
|
||||
* unbound, or not yet started), we only save the new state.
|
||||
* The gadget will be connected automatically when it is
|
||||
* activated/bound/started.
|
||||
*/
|
||||
gadget->connected = true;
|
||||
goto out;
|
||||
@ -724,22 +728,31 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_connect);
|
||||
|
||||
/**
|
||||
* usb_gadget_disconnect - software-controlled disconnect from USB host
|
||||
* @gadget:the peripheral being disconnected
|
||||
* usb_gadget_connect - software-controlled connect to USB host
|
||||
* @gadget:the peripheral being connected
|
||||
*
|
||||
* Disables the D+ (or potentially D-) pullup, which the host may see
|
||||
* as a disconnect (when a VBUS session is active). Not all systems
|
||||
* support software pullup controls.
|
||||
*
|
||||
* Following a successful disconnect, invoke the ->disconnect() callback
|
||||
* for the current gadget driver so that UDC drivers don't need to.
|
||||
* Enables the D+ (or potentially D-) pullup. The host will start
|
||||
* enumerating this gadget when the pullup is active and a VBUS session
|
||||
* is active (the link is powered).
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
int usb_gadget_connect(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
ret = usb_gadget_connect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_connect);
|
||||
|
||||
static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
|
||||
__must_hold(&gadget->udc->connect_lock)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -751,7 +764,7 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
if (!gadget->connected)
|
||||
goto out;
|
||||
|
||||
if (gadget->deactivated) {
|
||||
if (gadget->deactivated || !gadget->udc->started) {
|
||||
/*
|
||||
* If gadget is deactivated we only save new state.
|
||||
* Gadget will stay disconnected after activation.
|
||||
@ -774,6 +787,30 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_disconnect - software-controlled disconnect from USB host
|
||||
* @gadget:the peripheral being disconnected
|
||||
*
|
||||
* Disables the D+ (or potentially D-) pullup, which the host may see
|
||||
* as a disconnect (when a VBUS session is active). Not all systems
|
||||
* support software pullup controls.
|
||||
*
|
||||
* Following a successful disconnect, invoke the ->disconnect() callback
|
||||
* for the current gadget driver so that UDC drivers don't need to.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int usb_gadget_disconnect(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
ret = usb_gadget_disconnect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
|
||||
|
||||
/**
|
||||
@ -791,13 +828,14 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
if (gadget->deactivated)
|
||||
goto out;
|
||||
goto unlock;
|
||||
|
||||
if (gadget->connected) {
|
||||
ret = usb_gadget_disconnect(gadget);
|
||||
ret = usb_gadget_disconnect_locked(gadget);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* If gadget was being connected before deactivation, we want
|
||||
@ -807,7 +845,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
|
||||
}
|
||||
gadget->deactivated = true;
|
||||
|
||||
out:
|
||||
unlock:
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
trace_usb_gadget_deactivate(gadget, ret);
|
||||
|
||||
return ret;
|
||||
@ -827,8 +866,9 @@ int usb_gadget_activate(struct usb_gadget *gadget)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&gadget->udc->connect_lock);
|
||||
if (!gadget->deactivated)
|
||||
goto out;
|
||||
goto unlock;
|
||||
|
||||
gadget->deactivated = false;
|
||||
|
||||
@ -837,9 +877,11 @@ int usb_gadget_activate(struct usb_gadget *gadget)
|
||||
* while it was being deactivated, we call usb_gadget_connect().
|
||||
*/
|
||||
if (gadget->connected)
|
||||
ret = usb_gadget_connect(gadget);
|
||||
ret = usb_gadget_connect_locked(gadget);
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
|
||||
out:
|
||||
unlock:
|
||||
mutex_unlock(&gadget->udc->connect_lock);
|
||||
trace_usb_gadget_activate(gadget, ret);
|
||||
|
||||
return ret;
|
||||
@ -1078,12 +1120,22 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static void usb_udc_connect_control(struct usb_udc *udc)
|
||||
/* Acquire connect_lock before calling this function. */
|
||||
static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock)
|
||||
{
|
||||
if (udc->vbus)
|
||||
usb_gadget_connect(udc->gadget);
|
||||
usb_gadget_connect_locked(udc->gadget);
|
||||
else
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
usb_gadget_disconnect_locked(udc->gadget);
|
||||
}
|
||||
|
||||
static void vbus_event_work(struct work_struct *work)
|
||||
{
|
||||
struct usb_udc *udc = container_of(work, struct usb_udc, vbus_work);
|
||||
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_udc_connect_control_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1094,6 +1146,14 @@ static void usb_udc_connect_control(struct usb_udc *udc)
|
||||
*
|
||||
* The udc driver calls it when it wants to connect or disconnect gadget
|
||||
* according to vbus status.
|
||||
*
|
||||
* This function can be invoked from interrupt context by irq handlers of
|
||||
* the gadget drivers, however, usb_udc_connect_control() has to run in
|
||||
* non-atomic context due to the following:
|
||||
* a. Some of the gadget driver implementations expect the ->pullup
|
||||
* callback to be invoked in non-atomic context.
|
||||
* b. usb_gadget_disconnect() acquires udc_lock which is a mutex.
|
||||
* Hence offload invocation of usb_udc_connect_control() to workqueue.
|
||||
*/
|
||||
void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
|
||||
{
|
||||
@ -1101,7 +1161,7 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
|
||||
|
||||
if (udc) {
|
||||
udc->vbus = status;
|
||||
usb_udc_connect_control(udc);
|
||||
schedule_work(&udc->vbus_work);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
|
||||
@ -1124,7 +1184,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_start - tells usb device controller to start up
|
||||
* usb_gadget_udc_start_locked - tells usb device controller to start up
|
||||
* @udc: The UDC to be started
|
||||
*
|
||||
* This call is issued by the UDC Class driver when it's about
|
||||
@ -1135,8 +1195,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
|
||||
* necessary to have it powered on.
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller should acquire connect_lock before invoking this function.
|
||||
*/
|
||||
static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
|
||||
__must_hold(&udc->connect_lock)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1153,7 +1216,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_stop - tells usb device controller we don't need it anymore
|
||||
* usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore
|
||||
* @udc: The UDC to be stopped
|
||||
*
|
||||
* This call is issued by the UDC Class driver after calling
|
||||
@ -1162,8 +1225,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
|
||||
* The details are implementation specific, but it can go as
|
||||
* far as powering off UDC completely and disable its data
|
||||
* line pullups.
|
||||
*
|
||||
* Caller should acquire connect lock before invoking this function.
|
||||
*/
|
||||
static inline void usb_gadget_udc_stop(struct usb_udc *udc)
|
||||
static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc)
|
||||
__must_hold(&udc->connect_lock)
|
||||
{
|
||||
if (!udc->started) {
|
||||
dev_err(&udc->dev, "UDC had already stopped\n");
|
||||
@ -1322,12 +1388,14 @@ int usb_add_gadget(struct usb_gadget *gadget)
|
||||
|
||||
udc->gadget = gadget;
|
||||
gadget->udc = udc;
|
||||
mutex_init(&udc->connect_lock);
|
||||
|
||||
udc->started = false;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
mutex_unlock(&udc_lock);
|
||||
INIT_WORK(&udc->vbus_work, vbus_event_work);
|
||||
|
||||
ret = device_add(&udc->dev);
|
||||
if (ret)
|
||||
@ -1459,6 +1527,7 @@ void usb_del_gadget(struct usb_gadget *gadget)
|
||||
flush_work(&gadget->work);
|
||||
device_del(&gadget->dev);
|
||||
ida_free(&gadget_id_numbers, gadget->id_number);
|
||||
cancel_work_sync(&udc->vbus_work);
|
||||
device_unregister(&udc->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_del_gadget);
|
||||
@ -1523,11 +1592,16 @@ static int gadget_bind_driver(struct device *dev)
|
||||
if (ret)
|
||||
goto err_bind;
|
||||
|
||||
ret = usb_gadget_udc_start(udc);
|
||||
if (ret)
|
||||
mutex_lock(&udc->connect_lock);
|
||||
ret = usb_gadget_udc_start_locked(udc);
|
||||
if (ret) {
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
goto err_start;
|
||||
}
|
||||
usb_gadget_enable_async_callbacks(udc);
|
||||
usb_udc_connect_control(udc);
|
||||
udc->allow_connect = true;
|
||||
usb_udc_connect_control_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
return 0;
|
||||
@ -1558,12 +1632,16 @@ static void gadget_unbind_driver(struct device *dev)
|
||||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
|
||||
|
||||
usb_gadget_disconnect(gadget);
|
||||
udc->allow_connect = false;
|
||||
cancel_work_sync(&udc->vbus_work);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_disconnect_locked(gadget);
|
||||
usb_gadget_disable_async_callbacks(udc);
|
||||
if (gadget->irq)
|
||||
synchronize_irq(gadget->irq);
|
||||
udc->driver->unbind(gadget);
|
||||
usb_gadget_udc_stop(udc);
|
||||
usb_gadget_udc_stop_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
driver->is_bound = false;
|
||||
@ -1649,11 +1727,15 @@ static ssize_t soft_connect_store(struct device *dev,
|
||||
}
|
||||
|
||||
if (sysfs_streq(buf, "connect")) {
|
||||
usb_gadget_udc_start(udc);
|
||||
usb_gadget_connect(udc->gadget);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_udc_start_locked(udc);
|
||||
usb_gadget_connect_locked(udc->gadget);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
} else if (sysfs_streq(buf, "disconnect")) {
|
||||
usb_gadget_disconnect(udc->gadget);
|
||||
usb_gadget_udc_stop(udc);
|
||||
mutex_lock(&udc->connect_lock);
|
||||
usb_gadget_disconnect_locked(udc->gadget);
|
||||
usb_gadget_udc_stop_locked(udc);
|
||||
mutex_unlock(&udc->connect_lock);
|
||||
} else {
|
||||
dev_err(dev, "unsupported command '%s'\n", buf);
|
||||
ret = -EINVAL;
|
||||
|
@ -2877,9 +2877,9 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
||||
struct rzv2m_usb3drd *ddata = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
usb3->drd_reg = ddata->reg;
|
||||
ret = devm_request_irq(ddata->dev, ddata->drd_irq,
|
||||
ret = devm_request_irq(&pdev->dev, ddata->drd_irq,
|
||||
renesas_usb3_otg_irq, 0,
|
||||
dev_name(ddata->dev), usb3);
|
||||
dev_name(&pdev->dev), usb3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -248,6 +248,8 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_VENDOR_ID 0x2c7c
|
||||
/* These Quectel products use Quectel's vendor ID */
|
||||
#define QUECTEL_PRODUCT_EC21 0x0121
|
||||
#define QUECTEL_PRODUCT_EM061K_LTA 0x0123
|
||||
#define QUECTEL_PRODUCT_EM061K_LMS 0x0124
|
||||
#define QUECTEL_PRODUCT_EC25 0x0125
|
||||
#define QUECTEL_PRODUCT_EG91 0x0191
|
||||
#define QUECTEL_PRODUCT_EG95 0x0195
|
||||
@ -266,6 +268,8 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_PRODUCT_RM520N 0x0801
|
||||
#define QUECTEL_PRODUCT_EC200U 0x0901
|
||||
#define QUECTEL_PRODUCT_EC200S_CN 0x6002
|
||||
#define QUECTEL_PRODUCT_EM061K_LWW 0x6008
|
||||
#define QUECTEL_PRODUCT_EM061K_LCN 0x6009
|
||||
#define QUECTEL_PRODUCT_EC200T 0x6026
|
||||
#define QUECTEL_PRODUCT_RM500K 0x7001
|
||||
|
||||
@ -1189,6 +1193,18 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0x00, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x40) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
|
||||
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
|
||||
|
@ -95,7 +95,7 @@ peak_current_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t
|
||||
fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3;
|
||||
return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3);
|
||||
}
|
||||
static DEVICE_ATTR_RO(fast_role_swap_current);
|
||||
|
||||
|
@ -132,10 +132,8 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cci & UCSI_CCI_BUSY) {
|
||||
ucsi->ops->async_write(ucsi, UCSI_CANCEL, NULL, 0);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (cmd != UCSI_CANCEL && cci & UCSI_CCI_BUSY)
|
||||
return ucsi_exec_command(ucsi, UCSI_CANCEL);
|
||||
|
||||
if (!(cci & UCSI_CCI_COMMAND_COMPLETE))
|
||||
return -EIO;
|
||||
@ -149,6 +147,11 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
|
||||
return ucsi_read_error(ucsi);
|
||||
}
|
||||
|
||||
if (cmd == UCSI_CANCEL && cci & UCSI_CCI_CANCEL_COMPLETE) {
|
||||
ret = ucsi_acknowledge_command(ucsi);
|
||||
return ret ? ret : -EBUSY;
|
||||
}
|
||||
|
||||
return UCSI_CCI_LENGTH(cci);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user