USB fixes for 5.12-rc3
Here are a small number of USB fixes for 5.12-rc3 to resolve a bunch of reported issues: - usbip fixups for issues found by syzbot - xhci driver fixes and quirk additions - gadget driver fixes - dwc3 QCOM driver fix - usb-serial new ids and fixes - usblp fix for a long-time issue - cdc-acm quirk addition - other tiny fixes for reported problems All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYEzR3A8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylgSQCgjkrg8qFJLTss/PNe0/1zQIFNl2sAn2FyPV0y K34seYUf0LDj3OcXRLGl =72FI -----END PGP SIGNATURE----- Merge tag 'usb-5.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a small number of USB fixes for 5.12-rc3 to resolve a bunch of reported issues: - usbip fixups for issues found by syzbot - xhci driver fixes and quirk additions - gadget driver fixes - dwc3 QCOM driver fix - usb-serial new ids and fixes - usblp fix for a long-time issue - cdc-acm quirk addition - other tiny fixes for reported problems All of these have been in linux-next for a while with no reported issues" * tag 'usb-5.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (25 commits) xhci: Fix repeated xhci wake after suspend due to uncleared internal wake state usb: xhci: Fix ASMedia ASM1042A and ASM3242 DMA addressing xhci: Improve detection of device initiated wake signal. usb: xhci: do not perform Soft Retry for some xHCI hosts usbip: fix vudc usbip_sockfd_store races leading to gpf usbip: fix vhci_hcd attach_store() races leading to gpf usbip: fix stub_dev usbip_sockfd_store() races leading to gpf usbip: fix vudc to check for stream socket usbip: fix vhci_hcd to check for stream socket usbip: fix stub_dev to check for stream socket usb: dwc3: qcom: Add missing DWC3 OF node refcount decrement USB: usblp: fix a hang in poll() if disconnected USB: gadget: udc: s3c2410_udc: fix return value check in s3c2410_udc_probe() usb: renesas_usbhs: Clear PIPECFG for re-enabling pipe with other EPNUM usb: dwc3: qcom: Honor wakeup enabled/disabled state usb: gadget: f_uac1: stop playback on function disable usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio slot USB: gadget: u_ether: Fix a configfs return code usb: dwc3: qcom: add ACPI device id for sc8180x Goodix Fingerprint device is not a modem ...
This commit is contained in:
commit
5c7bdbf882
@ -1935,6 +1935,11 @@ static const struct usb_device_id acm_ids[] = {
|
||||
.driver_info = SEND_ZERO_PACKET,
|
||||
},
|
||||
|
||||
/* Exclude Goodix Fingerprint Reader */
|
||||
{ USB_DEVICE(0x27c6, 0x5395),
|
||||
.driver_info = IGNORE_DEVICE,
|
||||
},
|
||||
|
||||
/* control interfaces without any protocol set */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
|
||||
USB_CDC_PROTO_NONE) },
|
||||
|
@ -494,16 +494,24 @@ static int usblp_release(struct inode *inode, struct file *file)
|
||||
/* No kernel lock - fine */
|
||||
static __poll_t usblp_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
__poll_t ret;
|
||||
struct usblp *usblp = file->private_data;
|
||||
__poll_t ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
struct usblp *usblp = file->private_data;
|
||||
/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
|
||||
poll_wait(file, &usblp->rwait, wait);
|
||||
poll_wait(file, &usblp->wwait, wait);
|
||||
|
||||
mutex_lock(&usblp->mut);
|
||||
if (!usblp->present)
|
||||
ret |= EPOLLHUP;
|
||||
mutex_unlock(&usblp->mut);
|
||||
|
||||
spin_lock_irqsave(&usblp->lock, flags);
|
||||
ret = ((usblp->bidir && usblp->rcomplete) ? EPOLLIN | EPOLLRDNORM : 0) |
|
||||
((usblp->no_paper || usblp->wcomplete) ? EPOLLOUT | EPOLLWRNORM : 0);
|
||||
if (usblp->bidir && usblp->rcomplete)
|
||||
ret |= EPOLLIN | EPOLLRDNORM;
|
||||
if (usblp->no_paper || usblp->wcomplete)
|
||||
ret |= EPOLLOUT | EPOLLWRNORM;
|
||||
spin_unlock_irqrestore(&usblp->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
@ -358,8 +358,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
|
||||
if (ret)
|
||||
dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
|
||||
|
||||
if (device_may_wakeup(qcom->dev))
|
||||
dwc3_qcom_enable_interrupts(qcom);
|
||||
|
||||
qcom->is_suspended = true;
|
||||
dwc3_qcom_enable_interrupts(qcom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -372,7 +374,8 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
|
||||
if (!qcom->is_suspended)
|
||||
return 0;
|
||||
|
||||
dwc3_qcom_disable_interrupts(qcom);
|
||||
if (device_may_wakeup(qcom->dev))
|
||||
dwc3_qcom_disable_interrupts(qcom);
|
||||
|
||||
for (i = 0; i < qcom->num_clocks; i++) {
|
||||
ret = clk_prepare_enable(qcom->clks[i]);
|
||||
@ -650,16 +653,19 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 core - %d\n", ret);
|
||||
return ret;
|
||||
goto node_put;
|
||||
}
|
||||
|
||||
qcom->dwc3 = of_find_device_by_node(dwc3_np);
|
||||
if (!qcom->dwc3) {
|
||||
ret = -ENODEV;
|
||||
dev_err(dev, "failed to get dwc3 platform device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
node_put:
|
||||
of_node_put(dwc3_np);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_device *
|
||||
@ -938,6 +944,8 @@ static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
|
||||
static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
|
||||
{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
|
||||
{ "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
|
||||
{ "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
|
||||
{ "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
|
||||
|
@ -499,6 +499,7 @@ static void f_audio_disable(struct usb_function *f)
|
||||
uac1->as_out_alt = 0;
|
||||
uac1->as_in_alt = 0;
|
||||
|
||||
u_audio_stop_playback(&uac1->g_audio);
|
||||
u_audio_stop_capture(&uac1->g_audio);
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
|
||||
}
|
||||
|
||||
max_size_bw = num_channels(chmask) * ssize *
|
||||
DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
|
||||
((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
|
||||
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
|
||||
max_size_ep));
|
||||
|
||||
|
@ -182,12 +182,11 @@ out: \
|
||||
size_t len) \
|
||||
{ \
|
||||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int ret; \
|
||||
int ret = -EINVAL; \
|
||||
u8 val; \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
ret = sscanf(page, "%02hhx", &val); \
|
||||
if (ret > 0) { \
|
||||
if (sscanf(page, "%02hhx", &val) > 0) { \
|
||||
opts->_n_ = val; \
|
||||
ret = len; \
|
||||
} \
|
||||
|
@ -1773,8 +1773,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
||||
udc_info = dev_get_platdata(&pdev->dev);
|
||||
|
||||
base_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (!base_addr) {
|
||||
retval = -ENOMEM;
|
||||
if (IS_ERR(base_addr)) {
|
||||
retval = PTR_ERR(base_addr);
|
||||
goto err_mem;
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@
|
||||
#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
|
||||
#define PCI_DEVICE_ID_ASMEDIA_1142_XHCI 0x1242
|
||||
#define PCI_DEVICE_ID_ASMEDIA_2142_XHCI 0x2142
|
||||
#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242
|
||||
|
||||
static const char hcd_name[] = "xhci_hcd";
|
||||
|
||||
@ -276,11 +277,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI)
|
||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) {
|
||||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||||
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
||||
}
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
||||
(pdev->device == PCI_DEVICE_ID_ASMEDIA_1142_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_2142_XHCI))
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_2142_XHCI ||
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_3242_XHCI))
|
||||
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
||||
@ -295,6 +299,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
pdev->device == 0x9026)
|
||||
xhci->quirks |= XHCI_RESET_PLL_ON_DISCONNECT;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2 ||
|
||||
pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4))
|
||||
xhci->quirks |= XHCI_NO_SOFT_RETRY;
|
||||
|
||||
if (xhci->quirks & XHCI_RESET_ON_RESUME)
|
||||
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
|
||||
"QUIRK: Resetting on resume");
|
||||
|
@ -2484,7 +2484,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
remaining = 0;
|
||||
break;
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
|
||||
if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
|
||||
(ep_ring->err_count++ > MAX_SOFT_RETRY) ||
|
||||
le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
|
||||
break;
|
||||
|
||||
|
@ -883,44 +883,42 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
|
||||
xhci_set_cmd_ring_deq(xhci);
|
||||
}
|
||||
|
||||
static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
|
||||
/*
|
||||
* Disable port wake bits if do_wakeup is not set.
|
||||
*
|
||||
* Also clear a possible internal port wake state left hanging for ports that
|
||||
* detected termination but never successfully enumerated (trained to 0U).
|
||||
* Internal wake causes immediate xHCI wake after suspend. PORT_CSC write done
|
||||
* at enumeration clears this wake, force one here as well for unconnected ports
|
||||
*/
|
||||
|
||||
static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci,
|
||||
struct xhci_hub *rhub,
|
||||
bool do_wakeup)
|
||||
{
|
||||
struct xhci_port **ports;
|
||||
int port_index;
|
||||
unsigned long flags;
|
||||
u32 t1, t2, portsc;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
/* disable usb3 ports Wake bits */
|
||||
port_index = xhci->usb3_rhub.num_ports;
|
||||
ports = xhci->usb3_rhub.ports;
|
||||
while (port_index--) {
|
||||
t1 = readl(ports[port_index]->addr);
|
||||
portsc = t1;
|
||||
t1 = xhci_port_state_to_neutral(t1);
|
||||
t2 = t1 & ~PORT_WAKE_BITS;
|
||||
if (t1 != t2) {
|
||||
writel(t2, ports[port_index]->addr);
|
||||
xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
|
||||
xhci->usb3_rhub.hcd->self.busnum,
|
||||
port_index + 1, portsc, t2);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < rhub->num_ports; i++) {
|
||||
portsc = readl(rhub->ports[i]->addr);
|
||||
t1 = xhci_port_state_to_neutral(portsc);
|
||||
t2 = t1;
|
||||
|
||||
/* clear wake bits if do_wake is not set */
|
||||
if (!do_wakeup)
|
||||
t2 &= ~PORT_WAKE_BITS;
|
||||
|
||||
/* Don't touch csc bit if connected or connect change is set */
|
||||
if (!(portsc & (PORT_CSC | PORT_CONNECT)))
|
||||
t2 |= PORT_CSC;
|
||||
|
||||
/* disable usb2 ports Wake bits */
|
||||
port_index = xhci->usb2_rhub.num_ports;
|
||||
ports = xhci->usb2_rhub.ports;
|
||||
while (port_index--) {
|
||||
t1 = readl(ports[port_index]->addr);
|
||||
portsc = t1;
|
||||
t1 = xhci_port_state_to_neutral(t1);
|
||||
t2 = t1 & ~PORT_WAKE_BITS;
|
||||
if (t1 != t2) {
|
||||
writel(t2, ports[port_index]->addr);
|
||||
xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
|
||||
xhci->usb2_rhub.hcd->self.busnum,
|
||||
port_index + 1, portsc, t2);
|
||||
writel(t2, rhub->ports[i]->addr);
|
||||
xhci_dbg(xhci, "config port %d-%d wake bits, portsc: 0x%x, write: 0x%x\n",
|
||||
rhub->hcd->self.busnum, i + 1, portsc, t2);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
@ -983,8 +981,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
||||
return -EINVAL;
|
||||
|
||||
/* Clear root port wake on bits if wakeup not allowed. */
|
||||
if (!do_wakeup)
|
||||
xhci_disable_port_wake_on_bits(xhci);
|
||||
xhci_disable_hub_port_wake(xhci, &xhci->usb3_rhub, do_wakeup);
|
||||
xhci_disable_hub_port_wake(xhci, &xhci->usb2_rhub, do_wakeup);
|
||||
|
||||
if (!HCD_HW_ACCESSIBLE(hcd))
|
||||
return 0;
|
||||
@ -1088,6 +1086,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||
struct usb_hcd *secondary_hcd;
|
||||
int retval = 0;
|
||||
bool comp_timer_running = false;
|
||||
bool pending_portevent = false;
|
||||
|
||||
if (!hcd->state)
|
||||
return 0;
|
||||
@ -1226,13 +1225,22 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||
|
||||
done:
|
||||
if (retval == 0) {
|
||||
/* Resume root hubs only when have pending events. */
|
||||
if (xhci_pending_portevent(xhci)) {
|
||||
/*
|
||||
* Resume roothubs only if there are pending events.
|
||||
* USB 3 devices resend U3 LFPS wake after a 100ms delay if
|
||||
* the first wake signalling failed, give it that chance.
|
||||
*/
|
||||
pending_portevent = xhci_pending_portevent(xhci);
|
||||
if (!pending_portevent) {
|
||||
msleep(120);
|
||||
pending_portevent = xhci_pending_portevent(xhci);
|
||||
}
|
||||
|
||||
if (pending_portevent) {
|
||||
usb_hcd_resume_root_hub(xhci->shared_hcd);
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If system is subject to the Quirk, Compliance Mode Timer needs to
|
||||
* be re-initialized Always after a system resume. Ports are subject
|
||||
|
@ -1891,6 +1891,7 @@ struct xhci_hcd {
|
||||
#define XHCI_SKIP_PHY_INIT BIT_ULL(37)
|
||||
#define XHCI_DISABLE_SPARSE BIT_ULL(38)
|
||||
#define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
|
||||
#define XHCI_NO_SOFT_RETRY BIT_ULL(40)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
unsigned int limit_active_eps;
|
||||
|
@ -746,6 +746,8 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
|
||||
|
||||
void usbhs_pipe_free(struct usbhs_pipe *pipe)
|
||||
{
|
||||
usbhsp_pipe_select(pipe);
|
||||
usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0);
|
||||
usbhsp_put_pipe(pipe);
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x1a86, 0x7522) },
|
||||
{ USB_DEVICE(0x1a86, 0x7523) },
|
||||
{ USB_DEVICE(0x4348, 0x5523) },
|
||||
{ USB_DEVICE(0x9986, 0x7523) },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
@ -145,6 +145,7 @@ static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */
|
||||
{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
|
||||
{ USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
|
||||
{ USB_DEVICE(0x10C4, 0x88D8) }, /* Acuity Brands nLight Air Adapter */
|
||||
{ USB_DEVICE(0x10C4, 0x88FB) }, /* CESINEL MEDCAL STII Network Analyzer */
|
||||
{ USB_DEVICE(0x10C4, 0x8938) }, /* CESINEL MEDCAL S II Network Analyzer */
|
||||
{ USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
|
||||
@ -201,6 +202,8 @@ static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
|
||||
{ USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
|
||||
{ USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
|
||||
{ USB_DEVICE(0x1901, 0x0197) }, /* GE CS1000 Display serial interface */
|
||||
{ USB_DEVICE(0x1901, 0x0198) }, /* GE CS1000 M.2 Key E serial interface */
|
||||
{ USB_DEVICE(0x199B, 0xBA30) }, /* LORD WSDA-200-USB */
|
||||
{ USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
|
||||
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
|
||||
|
@ -3003,26 +3003,32 @@ static int edge_startup(struct usb_serial *serial)
|
||||
response = -ENODEV;
|
||||
}
|
||||
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
kfree(edge_serial->interrupt_in_buffer);
|
||||
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
kfree(edge_serial->bulk_in_buffer);
|
||||
|
||||
kfree(edge_serial);
|
||||
|
||||
return response;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* start interrupt read for this edgeport this interrupt will
|
||||
* continue as long as the edgeport is connected */
|
||||
response = usb_submit_urb(edge_serial->interrupt_read_urb,
|
||||
GFP_KERNEL);
|
||||
if (response)
|
||||
if (response) {
|
||||
dev_err(ddev, "%s - Error %d submitting control urb\n",
|
||||
__func__, response);
|
||||
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
||||
error:
|
||||
usb_free_urb(edge_serial->interrupt_read_urb);
|
||||
kfree(edge_serial->interrupt_in_buffer);
|
||||
|
||||
usb_free_urb(edge_serial->read_urb);
|
||||
kfree(edge_serial->bulk_in_buffer);
|
||||
|
||||
kfree(edge_serial);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
@ -545,37 +545,13 @@ static void xr_close(struct usb_serial_port *port)
|
||||
|
||||
static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_driver *driver = serial->type->usb_driver;
|
||||
struct usb_interface *control_interface;
|
||||
int ret;
|
||||
|
||||
/* Don't bind to control interface */
|
||||
if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* But claim the control interface during data interface probe */
|
||||
control_interface = usb_ifnum_to_if(serial->dev, 0);
|
||||
if (!control_interface)
|
||||
return -ENODEV;
|
||||
|
||||
ret = usb_driver_claim_interface(driver, control_interface, NULL);
|
||||
if (ret) {
|
||||
dev_err(&serial->interface->dev, "Failed to claim control interface\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xr_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_driver *driver = serial->type->usb_driver;
|
||||
struct usb_interface *control_interface;
|
||||
|
||||
control_interface = usb_ifnum_to_if(serial->dev, 0);
|
||||
usb_driver_release_interface(driver, control_interface);
|
||||
}
|
||||
|
||||
static const struct usb_device_id id_table[] = {
|
||||
{ USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */
|
||||
{ }
|
||||
@ -590,7 +566,6 @@ static struct usb_serial_driver xr_device = {
|
||||
.id_table = id_table,
|
||||
.num_ports = 1,
|
||||
.probe = xr_probe,
|
||||
.disconnect = xr_disconnect,
|
||||
.open = xr_open,
|
||||
.close = xr_close,
|
||||
.break_ctl = xr_break_ctl,
|
||||
|
@ -46,6 +46,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
int sockfd = 0;
|
||||
struct socket *socket;
|
||||
int rv;
|
||||
struct task_struct *tcp_rx = NULL;
|
||||
struct task_struct *tcp_tx = NULL;
|
||||
|
||||
if (!sdev) {
|
||||
dev_err(dev, "sdev is null\n");
|
||||
@ -69,23 +71,47 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
}
|
||||
|
||||
socket = sockfd_lookup(sockfd, &err);
|
||||
if (!socket)
|
||||
if (!socket) {
|
||||
dev_err(dev, "failed to lookup sock");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (socket->type != SOCK_STREAM) {
|
||||
dev_err(dev, "Expecting SOCK_STREAM - found %d",
|
||||
socket->type);
|
||||
goto sock_err;
|
||||
}
|
||||
|
||||
/* unlock and create threads and get tasks */
|
||||
spin_unlock_irq(&sdev->ud.lock);
|
||||
tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx");
|
||||
if (IS_ERR(tcp_rx)) {
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx");
|
||||
if (IS_ERR(tcp_tx)) {
|
||||
kthread_stop(tcp_rx);
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* get task structs now */
|
||||
get_task_struct(tcp_rx);
|
||||
get_task_struct(tcp_tx);
|
||||
|
||||
/* lock and update sdev->ud state */
|
||||
spin_lock_irq(&sdev->ud.lock);
|
||||
sdev->ud.tcp_socket = socket;
|
||||
sdev->ud.sockfd = sockfd;
|
||||
|
||||
spin_unlock_irq(&sdev->ud.lock);
|
||||
|
||||
sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
|
||||
"stub_rx");
|
||||
sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
|
||||
"stub_tx");
|
||||
|
||||
spin_lock_irq(&sdev->ud.lock);
|
||||
sdev->ud.tcp_rx = tcp_rx;
|
||||
sdev->ud.tcp_tx = tcp_tx;
|
||||
sdev->ud.status = SDEV_ST_USED;
|
||||
spin_unlock_irq(&sdev->ud.lock);
|
||||
|
||||
wake_up_process(sdev->ud.tcp_rx);
|
||||
wake_up_process(sdev->ud.tcp_tx);
|
||||
|
||||
} else {
|
||||
dev_info(dev, "stub down\n");
|
||||
|
||||
@ -100,6 +126,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
|
||||
return count;
|
||||
|
||||
sock_err:
|
||||
sockfd_put(socket);
|
||||
err:
|
||||
spin_unlock_irq(&sdev->ud.lock);
|
||||
return -EINVAL;
|
||||
|
@ -312,6 +312,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
struct vhci *vhci;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
struct task_struct *tcp_rx = NULL;
|
||||
struct task_struct *tcp_tx = NULL;
|
||||
|
||||
/*
|
||||
* @rhport: port number of vhci_hcd
|
||||
@ -349,12 +351,35 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
/* Extract socket from fd. */
|
||||
socket = sockfd_lookup(sockfd, &err);
|
||||
if (!socket)
|
||||
if (!socket) {
|
||||
dev_err(dev, "failed to lookup sock");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (socket->type != SOCK_STREAM) {
|
||||
dev_err(dev, "Expecting SOCK_STREAM - found %d",
|
||||
socket->type);
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* now need lock until setting vdev status as used */
|
||||
/* create threads before locking */
|
||||
tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
|
||||
if (IS_ERR(tcp_rx)) {
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
|
||||
if (IS_ERR(tcp_tx)) {
|
||||
kthread_stop(tcp_rx);
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* begin a lock */
|
||||
/* get task structs now */
|
||||
get_task_struct(tcp_rx);
|
||||
get_task_struct(tcp_tx);
|
||||
|
||||
/* now begin lock until setting vdev status set */
|
||||
spin_lock_irqsave(&vhci->lock, flags);
|
||||
spin_lock(&vdev->ud.lock);
|
||||
|
||||
@ -364,6 +389,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||
|
||||
sockfd_put(socket);
|
||||
kthread_stop_put(tcp_rx);
|
||||
kthread_stop_put(tcp_tx);
|
||||
|
||||
dev_err(dev, "port %d already used\n", rhport);
|
||||
/*
|
||||
@ -382,6 +409,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
vdev->speed = speed;
|
||||
vdev->ud.sockfd = sockfd;
|
||||
vdev->ud.tcp_socket = socket;
|
||||
vdev->ud.tcp_rx = tcp_rx;
|
||||
vdev->ud.tcp_tx = tcp_tx;
|
||||
vdev->ud.status = VDEV_ST_NOTASSIGNED;
|
||||
usbip_kcov_handle_init(&vdev->ud);
|
||||
|
||||
@ -389,8 +418,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
|
||||
spin_unlock_irqrestore(&vhci->lock, flags);
|
||||
/* end the lock */
|
||||
|
||||
vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
|
||||
vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
|
||||
wake_up_process(vdev->ud.tcp_rx);
|
||||
wake_up_process(vdev->ud.tcp_tx);
|
||||
|
||||
rh_port_connect(vdev, speed);
|
||||
|
||||
|
@ -90,8 +90,9 @@ unlock:
|
||||
}
|
||||
static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
|
||||
|
||||
static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *in, size_t count)
|
||||
static ssize_t usbip_sockfd_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *in, size_t count)
|
||||
{
|
||||
struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
|
||||
int rv;
|
||||
@ -100,6 +101,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
struct socket *socket;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
struct task_struct *tcp_rx = NULL;
|
||||
struct task_struct *tcp_tx = NULL;
|
||||
|
||||
rv = kstrtoint(in, 0, &sockfd);
|
||||
if (rv != 0)
|
||||
@ -138,24 +141,54 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
goto unlock_ud;
|
||||
}
|
||||
|
||||
udc->ud.tcp_socket = socket;
|
||||
if (socket->type != SOCK_STREAM) {
|
||||
dev_err(dev, "Expecting SOCK_STREAM - found %d",
|
||||
socket->type);
|
||||
ret = -EINVAL;
|
||||
goto sock_err;
|
||||
}
|
||||
|
||||
/* unlock and create threads and get tasks */
|
||||
spin_unlock_irq(&udc->ud.lock);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
udc->ud.tcp_rx = kthread_get_run(&v_rx_loop,
|
||||
&udc->ud, "vudc_rx");
|
||||
udc->ud.tcp_tx = kthread_get_run(&v_tx_loop,
|
||||
&udc->ud, "vudc_tx");
|
||||
tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx");
|
||||
if (IS_ERR(tcp_rx)) {
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx");
|
||||
if (IS_ERR(tcp_tx)) {
|
||||
kthread_stop(tcp_rx);
|
||||
sockfd_put(socket);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* get task structs now */
|
||||
get_task_struct(tcp_rx);
|
||||
get_task_struct(tcp_tx);
|
||||
|
||||
/* lock and update udc->ud state */
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
spin_lock_irq(&udc->ud.lock);
|
||||
|
||||
udc->ud.tcp_socket = socket;
|
||||
udc->ud.tcp_rx = tcp_rx;
|
||||
udc->ud.tcp_rx = tcp_tx;
|
||||
udc->ud.status = SDEV_ST_USED;
|
||||
|
||||
spin_unlock_irq(&udc->ud.lock);
|
||||
|
||||
ktime_get_ts64(&udc->start_time);
|
||||
v_start_timer(udc);
|
||||
udc->connected = 1;
|
||||
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
wake_up_process(udc->ud.tcp_rx);
|
||||
wake_up_process(udc->ud.tcp_tx);
|
||||
return count;
|
||||
|
||||
} else {
|
||||
if (!udc->connected) {
|
||||
dev_err(dev, "Device not connected");
|
||||
@ -177,6 +210,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||
|
||||
return count;
|
||||
|
||||
sock_err:
|
||||
sockfd_put(socket);
|
||||
unlock_ud:
|
||||
spin_unlock_irq(&udc->ud.lock);
|
||||
unlock:
|
||||
|
Loading…
Reference in New Issue
Block a user