Commit 0ecdd78c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull USB fixes from Greg KH:
 "Here are a number of small USB driver fixes for 5.4-rc5.

  More "fun" with some of the misc USB drivers as found by syzbot, and
  there are a number of other small bugfixes in here for reported
  issues.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: cdns3: Error out if USB_DR_MODE_UNKNOWN in cdns3_core_init_role()
  USB: ldusb: fix read info leaks
  USB: serial: ti_usb_3410_5052: clean up serial data access
  USB: serial: ti_usb_3410_5052: fix port-close races
  USB: usblp: fix use-after-free on disconnect
  usb: udc: lpc32xx: fix bad bit shift operation
  usb: cdns3: Fix dequeue implementation.
  USB: legousbtower: fix a signedness bug in tower_probe()
  USB: legousbtower: fix memleak on disconnect
  USB: ldusb: fix memleak on disconnect
parents 992cb107 97944769
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -166,7 +166,6 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
		goto err;

	switch (cdns->dr_mode) {
	case USB_DR_MODE_UNKNOWN:
	case USB_DR_MODE_OTG:
		ret = cdns3_hw_role_switch(cdns);
		if (ret)
@@ -182,6 +181,9 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
		if (ret)
			goto err;
		break;
	default:
		ret = -EINVAL;
		goto err;
	}

	return ret;
+20 −15
Original line number Diff line number Diff line
@@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
		request = cdns3_next_request(&priv_ep->pending_req_list);
		priv_req = to_cdns3_request(request);

		trb = priv_ep->trb_pool + priv_ep->dequeue;

		/* Request was dequeued and TRB was changed to TRB_LINK. */
		if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) {
			trace_cdns3_complete_trb(priv_ep, trb);
			cdns3_move_deq_to_next_trb(priv_req);
		}

		/* Re-select endpoint. It could be changed by other CPU during
		 * handling usb_gadget_giveback_request.
		 */
@@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
	struct usb_request *req, *req_temp;
	struct cdns3_request *priv_req;
	struct cdns3_trb *link_trb;
	u8 req_on_hw_ring = 0;
	unsigned long flags;
	int ret = 0;

@@ -2083,9 +2092,11 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,

	list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
				 list) {
		if (request == req)
		if (request == req) {
			req_on_hw_ring = 1;
			goto found;
		}
	}

	list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
				 list) {
@@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
	goto not_found;

found:

	if (priv_ep->wa1_trb == priv_req->trb)
		cdns3_wa1_restore_cycle_bit(priv_ep);

	link_trb = priv_req->trb;
	cdns3_move_deq_to_next_trb(priv_req);
	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);

	/* Update ring */
	request = cdns3_next_request(&priv_ep->deferred_req_list);
	if (request) {
		priv_req = to_cdns3_request(request);

	/* Update ring only if removed request is on pending_req_list list */
	if (req_on_hw_ring) {
		link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
					      (priv_req->start_trb * TRB_SIZE));
		link_trb->control = (link_trb->control & TRB_CYCLE) |
				    TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE;
	} else {
		priv_ep->flags |= EP_UPDATE_EP_TRBADDR;
				    TRB_TYPE(TRB_LINK) | TRB_CHAIN;

		if (priv_ep->wa1_trb == priv_req->trb)
			cdns3_wa1_restore_cycle_bit(priv_ep);
	}

	cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);

not_found:
	spin_unlock_irqrestore(&priv_dev->lock, flags);
	return ret;
+3 −1
Original line number Diff line number Diff line
@@ -445,6 +445,7 @@ static void usblp_cleanup(struct usblp *usblp)
	kfree(usblp->readbuf);
	kfree(usblp->device_id_string);
	kfree(usblp->statusbuf);
	usb_put_intf(usblp->intf);
	kfree(usblp);
}

@@ -1113,7 +1114,7 @@ static int usblp_probe(struct usb_interface *intf,
	init_waitqueue_head(&usblp->wwait);
	init_usb_anchor(&usblp->urbs);
	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
	usblp->intf = intf;
	usblp->intf = usb_get_intf(intf);

	/* Malloc device ID string buffer to the largest expected length,
	 * since we can re-query it on an ioctl and a dynamic string
@@ -1198,6 +1199,7 @@ abort:
	kfree(usblp->readbuf);
	kfree(usblp->statusbuf);
	kfree(usblp->device_id_string);
	usb_put_intf(usblp->intf);
	kfree(usblp);
abort_ret:
	return retval;
+3 −3
Original line number Diff line number Diff line
@@ -1177,11 +1177,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
			tmp = readl(USBD_RXDATA(udc->udp_baseaddr));

			bl = bytes - n;
			if (bl > 3)
				bl = 3;
			if (bl > 4)
				bl = 4;

			for (i = 0; i < bl; i++)
				data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
				data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF);
		}
		break;

+12 −11
Original line number Diff line number Diff line
@@ -380,10 +380,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
		goto exit;
	}

	if (mutex_lock_interruptible(&dev->mutex)) {
		retval = -ERESTARTSYS;
		goto exit;
	}
	mutex_lock(&dev->mutex);

	if (dev->open_count != 1) {
		retval = -ENODEV;
@@ -467,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,

	/* wait for data */
	spin_lock_irq(&dev->rbsl);
	if (dev->ring_head == dev->ring_tail) {
	while (dev->ring_head == dev->ring_tail) {
		dev->interrupt_in_done = 0;
		spin_unlock_irq(&dev->rbsl);
		if (file->f_flags & O_NONBLOCK) {
@@ -477,12 +474,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
		retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
		if (retval < 0)
			goto unlock_exit;
	} else {
		spin_unlock_irq(&dev->rbsl);

		spin_lock_irq(&dev->rbsl);
	}
	spin_unlock_irq(&dev->rbsl);

	/* actual_buffer contains actual_length + interrupt_in_buffer */
	actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
		retval = -EIO;
		goto unlock_exit;
	}
	bytes_to_read = min(count, *actual_buffer);
	if (bytes_to_read < *actual_buffer)
		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
@@ -693,8 +695,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
		dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");

	dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
	dev->ring_buffer =
		kmalloc_array(ring_buffer_size,
	dev->ring_buffer = kcalloc(ring_buffer_size,
			sizeof(size_t) + dev->interrupt_in_endpoint_size,
			GFP_KERNEL);
	if (!dev->ring_buffer)
Loading