USB fixes for 5.7-rc6

Here are a number of USB fixes for 5.7-rc6
 
 The "largest" in here is a bunch of raw-gadget fixes and api changes as
 the driver just showed up in -rc1 and work has been done to fix up some
 uapi issues found with the original submission, before it shows up in a
 -final release.
 
 Other than that, a bunch of other small USB gadget fixes, xhci fixes,
 some quirks, andother tiny fixes for reported issues.
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXsEF2A8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynrawCggmWnCKh2vFXUwIkyfDtS2HKm6q0AoMmBH76F
 isVpqHKAVOQ+LCDNhV6U
 =WzGX
 -----END PGP SIGNATURE-----

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

Pull USB fixes from Greg KH:
 "Here are a number of USB fixes for 5.7-rc6

  The "largest" in here is a bunch of raw-gadget fixes and api changes
  as the driver just showed up in -rc1 and work has been done to fix up
  some uapi issues found with the original submission, before it shows
  up in a -final release.

  Other than that, a bunch of other small USB gadget fixes, xhci fixes,
  some quirks, andother tiny fixes for reported issues.

  All of these have been in linux-next with no reported issues"

* tag 'usb-5.7-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (26 commits)
  USB: gadget: fix illegal array access in binding with UDC
  usb: core: hub: limit HUB_QUIRK_DISABLE_AUTOSUSPEND to USB5534B
  USB: usbfs: fix mmap dma mismatch
  usb: host: xhci-plat: keep runtime active when removing host
  usb: xhci: Fix NULL pointer dereference when enqueuing trbs from urb sg list
  usb: cdns3: gadget: make a bunch of functions static
  usb: mtu3: constify struct debugfs_reg32
  usb: gadget: udc: atmel: Make some symbols static
  usb: raw-gadget: fix null-ptr-deref when reenabling endpoints
  usb: raw-gadget: documentation updates
  usb: raw-gadget: support stalling/halting/wedging endpoints
  usb: raw-gadget: fix gadget endpoint selection
  usb: raw-gadget: improve uapi headers comments
  usb: typec: mux: intel: Fix DP_HPD_LVL bit field
  usb: raw-gadget: fix return value of ep read ioctls
  usb: dwc3: select USB_ROLE_SWITCH
  usb: gadget: legacy: fix error return code in gncm_bind()
  usb: gadget: legacy: fix error return code in cdc_bind()
  usb: gadget: legacy: fix redundant initialization warnings
  usb: gadget: tegra-xudc: Fix idle suspend/resume
  ...
This commit is contained in:
Linus Torvalds 2020-05-17 12:31:22 -07:00
commit fb27bc034d
22 changed files with 448 additions and 123 deletions

View File

@ -27,9 +27,8 @@ differences are:
3. Raw Gadget provides a way to select a UDC device/driver to bind to,
while GadgetFS currently binds to the first available UDC.
4. Raw Gadget uses predictable endpoint names (handles) across different
UDCs (as long as UDCs have enough endpoints of each required transfer
type).
4. Raw Gadget explicitly exposes information about endpoints addresses and
capabilities allowing a user to write UDC-agnostic gadgets.
5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
@ -50,12 +49,36 @@ The typical usage of Raw Gadget looks like:
Raw Gadget and react to those depending on what kind of USB device
needs to be emulated.
Note, that some UDC drivers have fixed addresses assigned to endpoints, and
therefore arbitrary endpoint addresses can't be used in the descriptors.
Nevertheles, Raw Gadget provides a UDC-agnostic way to write USB gadgets.
Once a USB_RAW_EVENT_CONNECT event is received via USB_RAW_IOCTL_EVENT_FETCH,
the USB_RAW_IOCTL_EPS_INFO ioctl can be used to find out information about
endpoints that the UDC driver has. Based on that information, the user must
chose UDC endpoints that will be used for the gadget being emulated, and
properly assign addresses in endpoint descriptors.
You can find usage examples (along with a test suite) here:
https://github.com/xairy/raw-gadget
Internal details
~~~~~~~~~~~~~~~~
Currently every endpoint read/write ioctl submits a USB request and waits until
its completion. This is the desired mode for coverage-guided fuzzing (as we'd
like all USB request processing happen during the lifetime of a syscall),
and must be kept in the implementation. (This might be slow for real world
applications, thus the O_NONBLOCK improvement suggestion below.)
Potential future improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Implement ioctl's for setting/clearing halt status on endpoints.
- Reporting more events (suspend, resume, etc.) through
USB_RAW_IOCTL_EVENT_FETCH.
- Report more events (suspend, resume, etc.) through USB_RAW_IOCTL_EVENT_FETCH.
- Support O_NONBLOCK I/O.
- Support USB 3 features (accept SS endpoint companion descriptor when
enabling endpoints; allow providing stream_id for bulk transfers).
- Support ISO transfer features (expose frame_number for completed requests).

View File

@ -82,7 +82,7 @@ static int cdns3_ep_run_stream_transfer(struct cdns3_endpoint *priv_ep,
* @ptr: address of device controller register to be read and changed
* @mask: bits requested to clar
*/
void cdns3_clear_register_bit(void __iomem *ptr, u32 mask)
static void cdns3_clear_register_bit(void __iomem *ptr, u32 mask)
{
mask = readl(ptr) & ~mask;
writel(mask, ptr);
@ -137,7 +137,7 @@ struct usb_request *cdns3_next_request(struct list_head *list)
*
* Returns buffer or NULL if no buffers in list
*/
struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list)
static struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list)
{
return list_first_entry_or_null(list, struct cdns3_aligned_buf, list);
}
@ -148,7 +148,7 @@ struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list)
*
* Returns request or NULL if no requests in list
*/
struct cdns3_request *cdns3_next_priv_request(struct list_head *list)
static struct cdns3_request *cdns3_next_priv_request(struct list_head *list)
{
return list_first_entry_or_null(list, struct cdns3_request, list);
}
@ -190,7 +190,7 @@ dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep,
return priv_ep->trb_pool_dma + offset;
}
int cdns3_ring_size(struct cdns3_endpoint *priv_ep)
static int cdns3_ring_size(struct cdns3_endpoint *priv_ep)
{
switch (priv_ep->type) {
case USB_ENDPOINT_XFER_ISOC:
@ -345,7 +345,7 @@ static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep)
cdns3_ep_inc_trb(&priv_ep->dequeue, &priv_ep->ccs, priv_ep->num_trbs);
}
void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
static void cdns3_move_deq_to_next_trb(struct cdns3_request *priv_req)
{
struct cdns3_endpoint *priv_ep = priv_req->priv_ep;
int current_trb = priv_req->start_trb;
@ -511,7 +511,7 @@ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
}
}
struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev,
static struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
{
@ -551,7 +551,7 @@ struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev,
return &priv_req->request;
}
int cdns3_wa2_gadget_ep_queue(struct cdns3_device *priv_dev,
static int cdns3_wa2_gadget_ep_queue(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep,
struct cdns3_request *priv_req)
{
@ -836,7 +836,7 @@ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep,
cdns3_gadget_ep_free_request(&priv_ep->endpoint, request);
}
void cdns3_wa1_restore_cycle_bit(struct cdns3_endpoint *priv_ep)
static void cdns3_wa1_restore_cycle_bit(struct cdns3_endpoint *priv_ep)
{
/* Work around for stale data address in TRB*/
if (priv_ep->wa1_set) {
@ -1904,7 +1904,7 @@ static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev,
return 0;
}
void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
static void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep)
{
if (!priv_ep->use_streams || priv_dev->gadget.speed < USB_SPEED_SUPER)
@ -1925,7 +1925,7 @@ void cdns3_stream_ep_reconfig(struct cdns3_device *priv_dev,
EP_CFG_TDL_CHK | EP_CFG_SID_CHK);
}
void cdns3_configure_dmult(struct cdns3_device *priv_dev,
static void cdns3_configure_dmult(struct cdns3_device *priv_dev,
struct cdns3_endpoint *priv_ep)
{
struct cdns3_usb_regs __iomem *regs = priv_dev->regs;
@ -2548,7 +2548,7 @@ found:
link_trb = priv_req->trb;
/* Update ring only if removed request is on pending_req_list list */
if (req_on_hw_ring) {
if (req_on_hw_ring && link_trb) {
link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
((priv_req->end_trb + 1) * TRB_SIZE));
link_trb->control = (link_trb->control & TRB_CYCLE) |

View File

@ -251,9 +251,19 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
usbm->vma_use_count = 1;
INIT_LIST_HEAD(&usbm->memlist);
if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle, size)) {
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
return -EAGAIN;
if (hcd->localmem_pool || !hcd_uses_dma(hcd)) {
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(usbm->mem) >> PAGE_SHIFT,
size, vma->vm_page_prot) < 0) {
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
return -EAGAIN;
}
} else {
if (dma_mmap_coherent(hcd->self.sysdev, vma, mem, dma_handle,
size)) {
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
return -EAGAIN;
}
}
vma->vm_flags |= VM_IO;

View File

@ -39,6 +39,7 @@
#define USB_VENDOR_GENESYS_LOGIC 0x05e3
#define USB_VENDOR_SMSC 0x0424
#define USB_PRODUCT_USB5534B 0x5534
#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
@ -5621,8 +5622,11 @@ out_hdev_lock:
}
static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS,
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_PRODUCT
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_SMSC,
.idProduct = USB_PRODUCT_USB5534B,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR

View File

@ -4,6 +4,7 @@ config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && HAS_DMA
select USB_XHCI_PLATFORM if USB_XHCI_HCD
select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.

View File

@ -114,6 +114,7 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
static const struct property_entry dwc3_pci_mrfld_properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "otg"),
PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
{}
};

View File

@ -2483,9 +2483,6 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
for_each_sg(sg, s, pending, i) {
trb = &dep->trb_pool[dep->trb_dequeue];
if (trb->ctrl & DWC3_TRB_CTRL_HWO)
break;
req->sg = sg_next(s);
req->num_pending_sgs--;

View File

@ -260,6 +260,9 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
char *name;
int ret;
if (strlen(page) < len)
return -EOVERFLOW;
name = kstrdup(page, GFP_KERNEL);
if (!name)
return -ENOMEM;

View File

@ -300,8 +300,10 @@ static int audio_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
if (!usb_desc)
if (!usb_desc) {
status = -ENOMEM;
goto fail;
}
usb_otg_descriptor_init(cdev->gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;

View File

@ -179,8 +179,10 @@ static int cdc_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(gadget);
if (!usb_desc)
if (!usb_desc) {
status = -ENOMEM;
goto fail1;
}
usb_otg_descriptor_init(gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;

View File

@ -1361,7 +1361,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
req->buf = dev->rbuf;
req->context = NULL;
value = -EOPNOTSUPP;
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
@ -1784,7 +1783,7 @@ static ssize_t
dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
{
struct dev_data *dev = fd->private_data;
ssize_t value = len, length = len;
ssize_t value, length = len;
unsigned total;
u32 tag;
char *kbuf;

View File

@ -156,8 +156,10 @@ static int gncm_bind(struct usb_composite_dev *cdev)
struct usb_descriptor_header *usb_desc;
usb_desc = usb_otg_descriptor_alloc(gadget);
if (!usb_desc)
if (!usb_desc) {
status = -ENOMEM;
goto fail;
}
usb_otg_descriptor_init(gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;

View File

@ -7,6 +7,7 @@
*/
#include <linux/compiler.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/kref.h>
@ -123,8 +124,6 @@ static void raw_event_queue_destroy(struct raw_event_queue *queue)
struct raw_dev;
#define USB_RAW_MAX_ENDPOINTS 32
enum ep_state {
STATE_EP_DISABLED,
STATE_EP_ENABLED,
@ -134,6 +133,7 @@ struct raw_ep {
struct raw_dev *dev;
enum ep_state state;
struct usb_ep *ep;
u8 addr;
struct usb_request *req;
bool urb_queued;
bool disabling;
@ -168,7 +168,8 @@ struct raw_dev {
bool ep0_out_pending;
bool ep0_urb_queued;
ssize_t ep0_status;
struct raw_ep eps[USB_RAW_MAX_ENDPOINTS];
struct raw_ep eps[USB_RAW_EPS_NUM_MAX];
int eps_num;
struct completion ep0_done;
struct raw_event_queue queue;
@ -202,8 +203,8 @@ static void dev_free(struct kref *kref)
usb_ep_free_request(dev->gadget->ep0, dev->req);
}
raw_event_queue_destroy(&dev->queue);
for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
if (dev->eps[i].state != STATE_EP_ENABLED)
for (i = 0; i < dev->eps_num; i++) {
if (dev->eps[i].state == STATE_EP_DISABLED)
continue;
usb_ep_disable(dev->eps[i].ep);
usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
@ -249,12 +250,26 @@ static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
complete(&dev->ep0_done);
}
static u8 get_ep_addr(const char *name)
{
/* If the endpoint has fixed function (named as e.g. "ep12out-bulk"),
* parse the endpoint address from its name. We deliberately use
* deprecated simple_strtoul() function here, as the number isn't
* followed by '\0' nor '\n'.
*/
if (isdigit(name[2]))
return simple_strtoul(&name[2], NULL, 10);
/* Otherwise the endpoint is configurable (named as e.g. "ep-a"). */
return USB_RAW_EP_ADDR_ANY;
}
static int gadget_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
int ret = 0;
int ret = 0, i = 0;
struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
struct usb_request *req;
struct usb_ep *ep;
unsigned long flags;
if (strcmp(gadget->name, dev->udc_name) != 0)
@ -273,6 +288,13 @@ static int gadget_bind(struct usb_gadget *gadget,
dev->req->context = dev;
dev->req->complete = gadget_ep0_complete;
dev->gadget = gadget;
gadget_for_each_ep(ep, dev->gadget) {
dev->eps[i].ep = ep;
dev->eps[i].addr = get_ep_addr(ep->name);
dev->eps[i].state = STATE_EP_DISABLED;
i++;
}
dev->eps_num = i;
spin_unlock_irqrestore(&dev->lock, flags);
/* Matches kref_put() in gadget_unbind(). */
@ -555,7 +577,7 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
if (copy_from_user(io, ptr, sizeof(*io)))
return ERR_PTR(-EFAULT);
if (io->ep >= USB_RAW_MAX_ENDPOINTS)
if (io->ep >= USB_RAW_EPS_NUM_MAX)
return ERR_PTR(-EINVAL);
if (!usb_raw_io_flags_valid(io->flags))
return ERR_PTR(-EINVAL);
@ -669,43 +691,61 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
if (IS_ERR(data))
return PTR_ERR(data);
ret = raw_process_ep0_io(dev, &io, data, false);
if (ret)
if (ret < 0)
goto free;
length = min(io.length, (unsigned int)ret);
if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
ret = -EFAULT;
else
ret = length;
free:
kfree(data);
return ret;
}
static bool check_ep_caps(struct usb_ep *ep,
struct usb_endpoint_descriptor *desc)
static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
{
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_ISOC:
if (!ep->caps.type_iso)
return false;
break;
case USB_ENDPOINT_XFER_BULK:
if (!ep->caps.type_bulk)
return false;
break;
case USB_ENDPOINT_XFER_INT:
if (!ep->caps.type_int)
return false;
break;
default:
return false;
int ret = 0;
unsigned long flags;
if (value)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
if (dev->state != STATE_DEV_RUNNING) {
dev_dbg(dev->dev, "fail, device is not running\n");
ret = -EINVAL;
goto out_unlock;
}
if (!dev->gadget) {
dev_dbg(dev->dev, "fail, gadget is not bound\n");
ret = -EBUSY;
goto out_unlock;
}
if (dev->ep0_urb_queued) {
dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
ret = -EBUSY;
goto out_unlock;
}
if (!dev->ep0_in_pending && !dev->ep0_out_pending) {
dev_dbg(&dev->gadget->dev, "fail, no request pending\n");
ret = -EBUSY;
goto out_unlock;
}
if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
return false;
if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
return false;
ret = usb_ep_set_halt(dev->gadget->ep0);
if (ret < 0)
dev_err(&dev->gadget->dev,
"fail, usb_ep_set_halt returned %d\n", ret);
return true;
if (dev->ep0_in_pending)
dev->ep0_in_pending = false;
else
dev->ep0_out_pending = false;
out_unlock:
spin_unlock_irqrestore(&dev->lock, flags);
return ret;
}
static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
@ -713,7 +753,7 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
int ret = 0, i;
unsigned long flags;
struct usb_endpoint_descriptor *desc;
struct usb_ep *ep = NULL;
struct raw_ep *ep;
desc = memdup_user((void __user *)value, sizeof(*desc));
if (IS_ERR(desc))
@ -741,41 +781,32 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
goto out_free;
}
for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
if (dev->eps[i].state == STATE_EP_ENABLED)
for (i = 0; i < dev->eps_num; i++) {
ep = &dev->eps[i];
if (ep->state != STATE_EP_DISABLED)
continue;
break;
}
if (i == USB_RAW_MAX_ENDPOINTS) {
dev_dbg(&dev->gadget->dev,
"fail, no device endpoints available\n");
ret = -EBUSY;
goto out_free;
}
gadget_for_each_ep(ep, dev->gadget) {
if (ep->enabled)
if (ep->addr != usb_endpoint_num(desc) &&
ep->addr != USB_RAW_EP_ADDR_ANY)
continue;
if (!check_ep_caps(ep, desc))
if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
continue;
ep->desc = desc;
ret = usb_ep_enable(ep);
ep->ep->desc = desc;
ret = usb_ep_enable(ep->ep);
if (ret < 0) {
dev_err(&dev->gadget->dev,
"fail, usb_ep_enable returned %d\n", ret);
goto out_free;
}
dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (!dev->eps[i].req) {
ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
if (!ep->req) {
dev_err(&dev->gadget->dev,
"fail, usb_ep_alloc_request failed\n");
usb_ep_disable(ep);
usb_ep_disable(ep->ep);
ret = -ENOMEM;
goto out_free;
}
dev->eps[i].ep = ep;
dev->eps[i].state = STATE_EP_ENABLED;
ep->driver_data = &dev->eps[i];
ep->state = STATE_EP_ENABLED;
ep->ep->driver_data = ep;
ret = i;
goto out_unlock;
}
@ -794,10 +825,6 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
{
int ret = 0, i = value;
unsigned long flags;
const void *desc;
if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS)
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
if (dev->state != STATE_DEV_RUNNING) {
@ -810,7 +837,12 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
ret = -EBUSY;
goto out_unlock;
}
if (dev->eps[i].state != STATE_EP_ENABLED) {
if (i < 0 || i >= dev->eps_num) {
dev_dbg(dev->dev, "fail, invalid endpoint\n");
ret = -EBUSY;
goto out_unlock;
}
if (dev->eps[i].state == STATE_EP_DISABLED) {
dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
ret = -EINVAL;
goto out_unlock;
@ -834,10 +866,8 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
spin_lock_irqsave(&dev->lock, flags);
usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
desc = dev->eps[i].ep->desc;
dev->eps[i].ep = NULL;
kfree(dev->eps[i].ep->desc);
dev->eps[i].state = STATE_EP_DISABLED;
kfree(desc);
dev->eps[i].disabling = false;
out_unlock:
@ -845,6 +875,74 @@ out_unlock:
return ret;
}
static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
unsigned long value, bool set, bool halt)
{
int ret = 0, i = value;
unsigned long flags;
spin_lock_irqsave(&dev->lock, flags);
if (dev->state != STATE_DEV_RUNNING) {
dev_dbg(dev->dev, "fail, device is not running\n");
ret = -EINVAL;
goto out_unlock;
}
if (!dev->gadget) {
dev_dbg(dev->dev, "fail, gadget is not bound\n");
ret = -EBUSY;
goto out_unlock;
}
if (i < 0 || i >= dev->eps_num) {
dev_dbg(dev->dev, "fail, invalid endpoint\n");
ret = -EBUSY;
goto out_unlock;
}
if (dev->eps[i].state == STATE_EP_DISABLED) {
dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
ret = -EINVAL;
goto out_unlock;
}
if (dev->eps[i].disabling) {
dev_dbg(&dev->gadget->dev,
"fail, disable is in progress\n");
ret = -EINVAL;
goto out_unlock;
}
if (dev->eps[i].urb_queued) {
dev_dbg(&dev->gadget->dev,
"fail, waiting for urb completion\n");
ret = -EINVAL;
goto out_unlock;
}
if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
dev_dbg(&dev->gadget->dev,
"fail, can't halt/wedge ISO endpoint\n");
ret = -EINVAL;
goto out_unlock;
}
if (set && halt) {
ret = usb_ep_set_halt(dev->eps[i].ep);
if (ret < 0)
dev_err(&dev->gadget->dev,
"fail, usb_ep_set_halt returned %d\n", ret);
} else if (!set && halt) {
ret = usb_ep_clear_halt(dev->eps[i].ep);
if (ret < 0)
dev_err(&dev->gadget->dev,
"fail, usb_ep_clear_halt returned %d\n", ret);
} else if (set && !halt) {
ret = usb_ep_set_wedge(dev->eps[i].ep);
if (ret < 0)
dev_err(&dev->gadget->dev,
"fail, usb_ep_set_wedge returned %d\n", ret);
}
out_unlock:
spin_unlock_irqrestore(&dev->lock, flags);
return ret;
}
static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
{
struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data;
@ -866,7 +964,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
{
int ret = 0;
unsigned long flags;
struct raw_ep *ep = &dev->eps[io->ep];
struct raw_ep *ep;
DECLARE_COMPLETION_ONSTACK(done);
spin_lock_irqsave(&dev->lock, flags);
@ -880,6 +978,12 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
ret = -EBUSY;
goto out_unlock;
}
if (io->ep >= dev->eps_num) {
dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
ret = -EINVAL;
goto out_unlock;
}
ep = &dev->eps[io->ep];
if (ep->state != STATE_EP_ENABLED) {
dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
ret = -EBUSY;
@ -964,12 +1068,14 @@ static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value)
if (IS_ERR(data))
return PTR_ERR(data);
ret = raw_process_ep_io(dev, &io, data, false);
if (ret)
if (ret < 0)
goto free;
length = min(io.length, (unsigned int)ret);
if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
ret = -EFAULT;
else
ret = length;
free:
kfree(data);
return ret;
@ -1023,6 +1129,71 @@ out_unlock:
return ret;
}
static void fill_ep_caps(struct usb_ep_caps *caps,
struct usb_raw_ep_caps *raw_caps)
{
raw_caps->type_control = caps->type_control;
raw_caps->type_iso = caps->type_iso;
raw_caps->type_bulk = caps->type_bulk;
raw_caps->type_int = caps->type_int;
raw_caps->dir_in = caps->dir_in;
raw_caps->dir_out = caps->dir_out;
}
static void fill_ep_limits(struct usb_ep *ep, struct usb_raw_ep_limits *limits)
{
limits->maxpacket_limit = ep->maxpacket_limit;
limits->max_streams = ep->max_streams;
}
static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
{
int ret = 0, i;
unsigned long flags;
struct usb_raw_eps_info *info;
struct raw_ep *ep;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
ret = -ENOMEM;
goto out;
}
spin_lock_irqsave(&dev->lock, flags);
if (dev->state != STATE_DEV_RUNNING) {
dev_dbg(dev->dev, "fail, device is not running\n");
ret = -EINVAL;
spin_unlock_irqrestore(&dev->lock, flags);
goto out_free;
}
if (!dev->gadget) {
dev_dbg(dev->dev, "fail, gadget is not bound\n");
ret = -EBUSY;
spin_unlock_irqrestore(&dev->lock, flags);
goto out_free;
}
memset(info, 0, sizeof(*info));
for (i = 0; i < dev->eps_num; i++) {
ep = &dev->eps[i];
strscpy(&info->eps[i].name[0], ep->ep->name,
USB_RAW_EP_NAME_MAX);
info->eps[i].addr = ep->addr;
fill_ep_caps(&ep->ep->caps, &info->eps[i].caps);
fill_ep_limits(ep->ep, &info->eps[i].limits);
}
ret = dev->eps_num;
spin_unlock_irqrestore(&dev->lock, flags);
if (copy_to_user((void __user *)value, info, sizeof(*info)))
ret = -EFAULT;
out_free:
kfree(info);
out:
return ret;
}
static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
{
struct raw_dev *dev = fd->private_data;
@ -1065,6 +1236,24 @@ static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
case USB_RAW_IOCTL_VBUS_DRAW:
ret = raw_ioctl_vbus_draw(dev, value);
break;
case USB_RAW_IOCTL_EPS_INFO:
ret = raw_ioctl_eps_info(dev, value);
break;
case USB_RAW_IOCTL_EP0_STALL:
ret = raw_ioctl_ep0_stall(dev, value);
break;
case USB_RAW_IOCTL_EP_SET_HALT:
ret = raw_ioctl_ep_set_clear_halt_wedge(
dev, value, true, true);
break;
case USB_RAW_IOCTL_EP_CLEAR_HALT:
ret = raw_ioctl_ep_set_clear_halt_wedge(
dev, value, false, true);
break;
case USB_RAW_IOCTL_EP_SET_WEDGE:
ret = raw_ioctl_ep_set_clear_halt_wedge(
dev, value, true, false);
break;
default:
ret = -EINVAL;
}

View File

@ -185,7 +185,7 @@ static int regs_dbg_release(struct inode *inode, struct file *file)
return 0;
}
const struct file_operations queue_dbg_fops = {
static const struct file_operations queue_dbg_fops = {
.owner = THIS_MODULE,
.open = queue_dbg_open,
.llseek = no_llseek,
@ -193,7 +193,7 @@ const struct file_operations queue_dbg_fops = {
.release = queue_dbg_release,
};
const struct file_operations regs_dbg_fops = {
static const struct file_operations regs_dbg_fops = {
.owner = THIS_MODULE,
.open = regs_dbg_open,
.llseek = generic_file_llseek,

View File

@ -2647,6 +2647,8 @@ net2272_plat_probe(struct platform_device *pdev)
err_req:
release_mem_region(base, len);
err:
kfree(dev);
return ret;
}

View File

@ -3840,11 +3840,11 @@ static int __maybe_unused tegra_xudc_suspend(struct device *dev)
flush_work(&xudc->usb_role_sw_work);
/* Forcibly disconnect before powergating. */
tegra_xudc_device_mode_off(xudc);
if (!pm_runtime_status_suspended(dev))
if (!pm_runtime_status_suspended(dev)) {
/* Forcibly disconnect before powergating. */
tegra_xudc_device_mode_off(xudc);
tegra_xudc_powergate(xudc);
}
pm_runtime_disable(dev);

View File

@ -362,6 +362,7 @@ static int xhci_plat_remove(struct platform_device *dev)
struct clk *reg_clk = xhci->reg_clk;
struct usb_hcd *shared_hcd = xhci->shared_hcd;
pm_runtime_get_sync(&dev->dev);
xhci->xhc_state |= XHCI_STATE_REMOVING;
usb_remove_hcd(shared_hcd);
@ -375,8 +376,9 @@ static int xhci_plat_remove(struct platform_device *dev)
clk_disable_unprepare(reg_clk);
usb_put_hcd(hcd);
pm_runtime_set_suspended(&dev->dev);
pm_runtime_disable(&dev->dev);
pm_runtime_put_noidle(&dev->dev);
pm_runtime_set_suspended(&dev->dev);
return 0;
}

View File

@ -3433,8 +3433,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* New sg entry */
--num_sgs;
sent_len -= block_len;
if (num_sgs != 0) {
sg = sg_next(sg);
sg = sg_next(sg);
if (num_sgs != 0 && sg) {
block_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
addr += sent_len;

View File

@ -276,7 +276,7 @@ static const struct file_operations mtu3_ep_fops = {
.release = single_release,
};
static struct debugfs_reg32 mtu3_prb_regs[] = {
static const struct debugfs_reg32 mtu3_prb_regs[] = {
dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0),
dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1),
dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2),
@ -349,7 +349,7 @@ static const struct file_operations mtu3_probe_fops = {
static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu)
{
struct ssusb_mtk *ssusb = mtu->ssusb;
struct debugfs_reg32 *regs;
const struct debugfs_reg32 *regs;
struct dentry *dir_prb;
int i;

View File

@ -377,7 +377,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq1, status);
return status;
goto err_put_regulator;
}
status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
@ -386,8 +386,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq2, status);
free_irq(twl->irq1, twl);
return status;
goto err_free_irq1;
}
twl->asleep = 0;
@ -396,6 +395,13 @@ static int twl6030_usb_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
return 0;
err_free_irq1:
free_irq(twl->irq1, twl);
err_put_regulator:
regulator_put(twl->usb3v3);
return status;
}
static int twl6030_usb_remove(struct platform_device *pdev)

View File

@ -63,6 +63,7 @@ enum {
#define PMC_USB_ALTMODE_DP_MODE_SHIFT 8
/* TBT specific Mode Data bits */
#define PMC_USB_ALTMODE_HPD_HIGH BIT(14)
#define PMC_USB_ALTMODE_TBT_TYPE BIT(17)
#define PMC_USB_ALTMODE_CABLE_TYPE BIT(18)
#define PMC_USB_ALTMODE_ACTIVE_LINK BIT(20)
@ -74,8 +75,8 @@ enum {
#define PMC_USB_ALTMODE_TBT_GEN(_g_) (((_g_) & GENMASK(1, 0)) << 28)
/* Display HPD Request bits */
#define PMC_USB_DP_HPD_LVL BIT(4)
#define PMC_USB_DP_HPD_IRQ BIT(5)
#define PMC_USB_DP_HPD_LVL BIT(6)
struct pmc_usb;
@ -158,8 +159,7 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
PMC_USB_ALTMODE_DP_MODE_SHIFT;
if (data->status & DP_STATUS_HPD_STATE)
req.mode_data |= PMC_USB_DP_HPD_LVL <<
PMC_USB_ALTMODE_DP_MODE_SHIFT;
req.mode_data |= PMC_USB_ALTMODE_HPD_HIGH;
return pmc_usb_command(port, (void *)&req, sizeof(req));
}

View File

@ -93,6 +93,64 @@ struct usb_raw_ep_io {
__u8 data[0];
};
/* Maximum number of non-control endpoints in struct usb_raw_eps_info. */
#define USB_RAW_EPS_NUM_MAX 30
/* Maximum length of UDC endpoint name in struct usb_raw_ep_info. */
#define USB_RAW_EP_NAME_MAX 16
/* Used as addr in struct usb_raw_ep_info if endpoint accepts any address. */
#define USB_RAW_EP_ADDR_ANY 0xff
/*
* struct usb_raw_ep_caps - exposes endpoint capabilities from struct usb_ep
* (technically from its member struct usb_ep_caps).
*/
struct usb_raw_ep_caps {
__u32 type_control : 1;
__u32 type_iso : 1;
__u32 type_bulk : 1;
__u32 type_int : 1;
__u32 dir_in : 1;
__u32 dir_out : 1;
};
/*
* struct usb_raw_ep_limits - exposes endpoint limits from struct usb_ep.
* @maxpacket_limit: Maximum packet size value supported by this endpoint.
* @max_streams: maximum number of streams supported by this endpoint
* (actual number is 2^n).
* @reserved: Empty, reserved for potential future extensions.
*/
struct usb_raw_ep_limits {
__u16 maxpacket_limit;
__u16 max_streams;
__u32 reserved;
};
/*
* struct usb_raw_ep_info - stores information about a gadget endpoint.
* @name: Name of the endpoint as it is defined in the UDC driver.
* @addr: Address of the endpoint that must be specified in the endpoint
* descriptor passed to USB_RAW_IOCTL_EP_ENABLE ioctl.
* @caps: Endpoint capabilities.
* @limits: Endpoint limits.
*/
struct usb_raw_ep_info {
__u8 name[USB_RAW_EP_NAME_MAX];
__u32 addr;
struct usb_raw_ep_caps caps;
struct usb_raw_ep_limits limits;
};
/*
* struct usb_raw_eps_info - argument for USB_RAW_IOCTL_EPS_INFO ioctl.
* eps: Structures that store information about non-control endpoints.
*/
struct usb_raw_eps_info {
struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};
/*
* Initializes a Raw Gadget instance.
* Accepts a pointer to the usb_raw_init struct as an argument.
@ -115,37 +173,38 @@ struct usb_raw_ep_io {
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
/*
* Queues an IN (OUT for READ) urb as a response to the last control request
* received on endpoint 0, provided that was an IN (OUT for READ) request and
* waits until the urb is completed. Copies received data to user for READ.
* Queues an IN (OUT for READ) request as a response to the last setup request
* received on endpoint 0 (provided that was an IN (OUT for READ) request), and
* waits until the request is completed. Copies received data to user for READ.
* Accepts a pointer to the usb_raw_ep_io struct as an argument.
* Returns length of trasferred data on success or negative error code on
* Returns length of transferred data on success or negative error code on
* failure.
*/
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
/*
* Finds an endpoint that supports the transfer type specified in the
* descriptor and enables it.
* Accepts a pointer to the usb_endpoint_descriptor struct as an argument.
* Finds an endpoint that satisfies the parameters specified in the provided
* descriptors (address, transfer type, etc.) and enables it.
* Accepts a pointer to the usb_raw_ep_descs struct as an argument.
* Returns enabled endpoint handle on success or negative error code on failure.
*/
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
/* Disables specified endpoint.
/*
* Disables specified endpoint.
* Accepts endpoint handle as an argument.
* Returns 0 on success or negative error code on failure.
*/
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
/*
* Queues an IN (OUT for READ) urb as a response to the last control request
* received on endpoint usb_raw_ep_io.ep, provided that was an IN (OUT for READ)
* request and waits until the urb is completed. Copies received data to user
* for READ.
* Queues an IN (OUT for READ) request as a response to the last setup request
* received on endpoint usb_raw_ep_io.ep (provided that was an IN (OUT for READ)
* request), and waits until the request is completed. Copies received data to
* user for READ.
* Accepts a pointer to the usb_raw_ep_io struct as an argument.
* Returns length of trasferred data on success or negative error code on
* Returns length of transferred data on success or negative error code on
* failure.
*/
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
@ -164,4 +223,27 @@ struct usb_raw_ep_io {
*/
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
/*
* Fills in the usb_raw_eps_info structure with information about non-control
* endpoints available for the currently connected UDC.
* Returns the number of available endpoints on success or negative error code
* on failure.
*/
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
/*
* Stalls a pending control request on endpoint 0.
* Returns 0 on success or negative error code on failure.
*/
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
/*
* Sets or clears halt or wedge status of the endpoint.
* Accepts endpoint handle as an argument.
* Returns 0 on success or negative error code on failure.
*/
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)
#endif /* _UAPI__LINUX_USB_RAW_GADGET_H */