USB fixes for 5.4-rc5
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXbSNXA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylrbgCfdgF24UtCBMI1P5E+gFOVhuPg+vIAniTEHMRZ iZqdtEh5mJNPoWzE8wRd =9utt -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
0ecdd78c75
|
@ -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;
|
||||
|
|
|
@ -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,8 +2092,10 @@ 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,
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,10 +695,9 @@ 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,
|
||||
sizeof(size_t) + dev->interrupt_in_endpoint_size,
|
||||
GFP_KERNEL);
|
||||
dev->ring_buffer = kcalloc(ring_buffer_size,
|
||||
sizeof(size_t) + dev->interrupt_in_endpoint_size,
|
||||
GFP_KERNEL);
|
||||
if (!dev->ring_buffer)
|
||||
goto error;
|
||||
dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
|
||||
|
|
|
@ -419,10 +419,7 @@ static int tower_release (struct inode *inode, struct file *file)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (mutex_lock_interruptible(&dev->lock)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
}
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
if (dev->open_count != 1) {
|
||||
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
|
|||
get_version_reply,
|
||||
sizeof(*get_version_reply),
|
||||
1000);
|
||||
if (result < sizeof(*get_version_reply)) {
|
||||
if (result != sizeof(*get_version_reply)) {
|
||||
if (result >= 0)
|
||||
result = -EIO;
|
||||
dev_err(idev, "get version request failed: %d\n", result);
|
||||
|
|
|
@ -776,7 +776,6 @@ static void ti_close(struct usb_serial_port *port)
|
|||
struct ti_port *tport;
|
||||
int port_number;
|
||||
int status;
|
||||
int do_unlock;
|
||||
unsigned long flags;
|
||||
|
||||
tdev = usb_get_serial_data(port->serial);
|
||||
|
@ -800,16 +799,13 @@ static void ti_close(struct usb_serial_port *port)
|
|||
"%s - cannot send close port command, %d\n"
|
||||
, __func__, status);
|
||||
|
||||
/* if mutex_lock is interrupted, continue anyway */
|
||||
do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
|
||||
--tport->tp_tdev->td_open_port_count;
|
||||
if (tport->tp_tdev->td_open_port_count <= 0) {
|
||||
mutex_lock(&tdev->td_open_close_lock);
|
||||
--tdev->td_open_port_count;
|
||||
if (tdev->td_open_port_count == 0) {
|
||||
/* last port is closed, shut down interrupt 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue