2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-23 04:34:11 +08:00

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:
Linus Torvalds 2021-03-13 12:32:57 -08:00
commit 5c7bdbf882
19 changed files with 229 additions and 110 deletions

View File

@ -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) },

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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));

View File

@ -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; \
} \

View File

@ -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;
}

View File

@ -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");

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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: