Commit 0ecdd78c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

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
...@@ -166,7 +166,6 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -166,7 +166,6 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
goto err; goto err;
switch (cdns->dr_mode) { switch (cdns->dr_mode) {
case USB_DR_MODE_UNKNOWN:
case USB_DR_MODE_OTG: case USB_DR_MODE_OTG:
ret = cdns3_hw_role_switch(cdns); ret = cdns3_hw_role_switch(cdns);
if (ret) if (ret)
...@@ -182,6 +181,9 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -182,6 +181,9 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
if (ret) if (ret)
goto err; goto err;
break; break;
default:
ret = -EINVAL;
goto err;
} }
return ret; return ret;
......
...@@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, ...@@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
request = cdns3_next_request(&priv_ep->pending_req_list); request = cdns3_next_request(&priv_ep->pending_req_list);
priv_req = to_cdns3_request(request); 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 /* Re-select endpoint. It could be changed by other CPU during
* handling usb_gadget_giveback_request. * handling usb_gadget_giveback_request.
*/ */
...@@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
struct usb_request *req, *req_temp; struct usb_request *req, *req_temp;
struct cdns3_request *priv_req; struct cdns3_request *priv_req;
struct cdns3_trb *link_trb; struct cdns3_trb *link_trb;
u8 req_on_hw_ring = 0;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
...@@ -2083,9 +2092,11 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -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_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list,
list) { list) {
if (request == req) if (request == req) {
req_on_hw_ring = 1;
goto found; goto found;
} }
}
list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list, list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list,
list) { list) {
...@@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, ...@@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
goto not_found; goto not_found;
found: found:
if (priv_ep->wa1_trb == priv_req->trb)
cdns3_wa1_restore_cycle_bit(priv_ep);
link_trb = priv_req->trb; 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 + link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
(priv_req->start_trb * TRB_SIZE)); (priv_req->start_trb * TRB_SIZE));
link_trb->control = (link_trb->control & TRB_CYCLE) | link_trb->control = (link_trb->control & TRB_CYCLE) |
TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE; TRB_TYPE(TRB_LINK) | TRB_CHAIN;
} else {
priv_ep->flags |= EP_UPDATE_EP_TRBADDR; 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: not_found:
spin_unlock_irqrestore(&priv_dev->lock, flags); spin_unlock_irqrestore(&priv_dev->lock, flags);
return ret; return ret;
......
...@@ -445,6 +445,7 @@ static void usblp_cleanup(struct usblp *usblp) ...@@ -445,6 +445,7 @@ static void usblp_cleanup(struct usblp *usblp)
kfree(usblp->readbuf); kfree(usblp->readbuf);
kfree(usblp->device_id_string); kfree(usblp->device_id_string);
kfree(usblp->statusbuf); kfree(usblp->statusbuf);
usb_put_intf(usblp->intf);
kfree(usblp); kfree(usblp);
} }
...@@ -1113,7 +1114,7 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -1113,7 +1114,7 @@ static int usblp_probe(struct usb_interface *intf,
init_waitqueue_head(&usblp->wwait); init_waitqueue_head(&usblp->wwait);
init_usb_anchor(&usblp->urbs); init_usb_anchor(&usblp->urbs);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; 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, /* Malloc device ID string buffer to the largest expected length,
* since we can re-query it on an ioctl and a dynamic string * since we can re-query it on an ioctl and a dynamic string
...@@ -1198,6 +1199,7 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -1198,6 +1199,7 @@ static int usblp_probe(struct usb_interface *intf,
kfree(usblp->readbuf); kfree(usblp->readbuf);
kfree(usblp->statusbuf); kfree(usblp->statusbuf);
kfree(usblp->device_id_string); kfree(usblp->device_id_string);
usb_put_intf(usblp->intf);
kfree(usblp); kfree(usblp);
abort_ret: abort_ret:
return retval; return retval;
......
...@@ -1177,11 +1177,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) ...@@ -1177,11 +1177,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
bl = bytes - n; bl = bytes - n;
if (bl > 3) if (bl > 4)
bl = 3; bl = 4;
for (i = 0; i < bl; i++) for (i = 0; i < bl; i++)
data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF);
} }
break; break;
......
...@@ -380,10 +380,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) ...@@ -380,10 +380,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
goto exit; goto exit;
} }
if (mutex_lock_interruptible(&dev->mutex)) { mutex_lock(&dev->mutex);
retval = -ERESTARTSYS;
goto exit;
}
if (dev->open_count != 1) { if (dev->open_count != 1) {
retval = -ENODEV; retval = -ENODEV;
...@@ -467,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, ...@@ -467,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
/* wait for data */ /* wait for data */
spin_lock_irq(&dev->rbsl); spin_lock_irq(&dev->rbsl);
if (dev->ring_head == dev->ring_tail) { while (dev->ring_head == dev->ring_tail) {
dev->interrupt_in_done = 0; dev->interrupt_in_done = 0;
spin_unlock_irq(&dev->rbsl); spin_unlock_irq(&dev->rbsl);
if (file->f_flags & O_NONBLOCK) { 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, ...@@ -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); retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
if (retval < 0) if (retval < 0)
goto unlock_exit; 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 contains actual_length + interrupt_in_buffer */
actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size)); 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); bytes_to_read = min(count, *actual_buffer);
if (bytes_to_read < *actual_buffer) if (bytes_to_read < *actual_buffer)
dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n", 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 * ...@@ -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_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->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
dev->ring_buffer = dev->ring_buffer = kcalloc(ring_buffer_size,
kmalloc_array(ring_buffer_size,
sizeof(size_t) + dev->interrupt_in_endpoint_size, sizeof(size_t) + dev->interrupt_in_endpoint_size,
GFP_KERNEL); GFP_KERNEL);
if (!dev->ring_buffer) if (!dev->ring_buffer)
......
...@@ -419,10 +419,7 @@ static int tower_release (struct inode *inode, struct file *file) ...@@ -419,10 +419,7 @@ static int tower_release (struct inode *inode, struct file *file)
goto exit; goto exit;
} }
if (mutex_lock_interruptible(&dev->lock)) { mutex_lock(&dev->lock);
retval = -ERESTARTSYS;
goto exit;
}
if (dev->open_count != 1) { if (dev->open_count != 1) {
dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n", dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
...@@ -881,7 +878,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device ...@@ -881,7 +878,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
get_version_reply, get_version_reply,
sizeof(*get_version_reply), sizeof(*get_version_reply),
1000); 1000);
if (result < sizeof(*get_version_reply)) { if (result != sizeof(*get_version_reply)) {
if (result >= 0) if (result >= 0)
result = -EIO; result = -EIO;
dev_err(idev, "get version request failed: %d\n", result); dev_err(idev, "get version request failed: %d\n", result);
......
...@@ -776,7 +776,6 @@ static void ti_close(struct usb_serial_port *port) ...@@ -776,7 +776,6 @@ static void ti_close(struct usb_serial_port *port)
struct ti_port *tport; struct ti_port *tport;
int port_number; int port_number;
int status; int status;
int do_unlock;
unsigned long flags; unsigned long flags;
tdev = usb_get_serial_data(port->serial); tdev = usb_get_serial_data(port->serial);
...@@ -800,15 +799,12 @@ static void ti_close(struct usb_serial_port *port) ...@@ -800,15 +799,12 @@ static void ti_close(struct usb_serial_port *port)
"%s - cannot send close port command, %d\n" "%s - cannot send close port command, %d\n"
, __func__, status); , __func__, status);
/* if mutex_lock is interrupted, continue anyway */ mutex_lock(&tdev->td_open_close_lock);
do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); --tdev->td_open_port_count;
--tport->tp_tdev->td_open_port_count; if (tdev->td_open_port_count == 0) {
if (tport->tp_tdev->td_open_port_count <= 0) {
/* last port is closed, shut down interrupt urb */ /* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb); usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
tport->tp_tdev->td_open_port_count = 0;
} }
if (do_unlock)
mutex_unlock(&tdev->td_open_close_lock); mutex_unlock(&tdev->td_open_close_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment