mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-27 20:07:09 +00:00
USB fixes for 4.14-rc4
Here are a number of USB fixes for 4.14-rc4 to resolved reported issue. There's a bunch of stuff in here based on the great work Andrey Konovalov is doing in fuzzing the USB stack. Lots of bug fixes when dealing with corrupted USB descriptors that we've never seen in "normal" operation, but is now ensuring the stack is much more hardened overall. There's also the usual XHCI and gadget driver fixes as well, and a build error fix, and a few other minor things, full details in the shortlog. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWdN/yw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yl6pQCdGY+nPJhzj9EIeFj5QUpSuS4b1pYAoKrbNn+V CMpg4iG1oXUtVL8jBbKa =fVpl -----END PGP SIGNATURE----- Merge tag 'usb-4.14-rc4' 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 4.14-rc4 to resolved reported issues. There's a bunch of stuff in here based on the great work Andrey Konovalov is doing in fuzzing the USB stack. Lots of bug fixes when dealing with corrupted USB descriptors that we've never seen in "normal" operation, but is now ensuring the stack is much more hardened overall. There's also the usual XHCI and gadget driver fixes as well, and a build error fix, and a few other minor things, full details in the shortlog. All of these have been in linux-next with no reported issues" * tag 'usb-4.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (38 commits) usb: dwc3: of-simple: Add compatible for Spreadtrum SC9860 platform usb: gadget: udc: atmel: set vbus irqflags explicitly usb: gadget: ffs: handle I/O completion in-order usb: renesas_usbhs: fix usbhsf_fifo_clear() for RX direction usb: renesas_usbhs: fix the BCLR setting condition for non-DCP pipe usb: gadget: udc: renesas_usb3: Fix return value of usb3_write_pipe() usb: gadget: udc: renesas_usb3: fix Pn_RAMMAP.Pn_MPKT value usb: gadget: udc: renesas_usb3: fix for no-data control transfer USB: dummy-hcd: Fix erroneous synchronization change USB: dummy-hcd: fix infinite-loop resubmission bug USB: dummy-hcd: fix connection failures (wrong speed) USB: cdc-wdm: ignore -EPIPE from GetEncapsulatedResponse USB: devio: Don't corrupt user memory USB: devio: Prevent integer overflow in proc_do_submiturb() USB: g_mass_storage: Fix deadlock when driver is unbound USB: gadgetfs: Fix crash caused by inadequate synchronization USB: gadgetfs: fix copy_to_user while holding spinlock USB: uas: fix bug in handling of alternate settings usb-storage: unusual_devs entry to fix write-access regression for Seagate external drives usb-storage: fix bogus hardware error messages for ATA pass-thru devices ...
This commit is contained in:
commit
887c8ba753
@ -190,8 +190,10 @@ static void wdm_in_callback(struct urb *urb)
|
||||
/*
|
||||
* only set a new error if there is no previous error.
|
||||
* Errors are only cleared during read/open
|
||||
* Avoid propagating -EPIPE (stall) to userspace since it is
|
||||
* better handled as an empty read
|
||||
*/
|
||||
if (desc->rerr == 0)
|
||||
if (desc->rerr == 0 && status != -EPIPE)
|
||||
desc->rerr = status;
|
||||
|
||||
if (length + desc->length > desc->wMaxCommand) {
|
||||
|
@ -643,15 +643,23 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
|
||||
|
||||
} else if (header->bDescriptorType ==
|
||||
USB_DT_INTERFACE_ASSOCIATION) {
|
||||
struct usb_interface_assoc_descriptor *d;
|
||||
|
||||
d = (struct usb_interface_assoc_descriptor *)header;
|
||||
if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
|
||||
dev_warn(ddev,
|
||||
"config %d has an invalid interface association descriptor of length %d, skipping\n",
|
||||
cfgno, d->bLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iad_num == USB_MAXIADS) {
|
||||
dev_warn(ddev, "found more Interface "
|
||||
"Association Descriptors "
|
||||
"than allocated for in "
|
||||
"configuration %d\n", cfgno);
|
||||
} else {
|
||||
config->intf_assoc[iad_num] =
|
||||
(struct usb_interface_assoc_descriptor
|
||||
*)header;
|
||||
config->intf_assoc[iad_num] = d;
|
||||
iad_num++;
|
||||
}
|
||||
|
||||
@ -852,7 +860,7 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
}
|
||||
|
||||
if (dev->quirks & USB_QUIRK_DELAY_INIT)
|
||||
msleep(100);
|
||||
msleep(200);
|
||||
|
||||
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
|
||||
bigbuffer, length);
|
||||
|
@ -140,6 +140,9 @@ module_param(usbfs_memory_mb, uint, 0644);
|
||||
MODULE_PARM_DESC(usbfs_memory_mb,
|
||||
"maximum MB allowed for usbfs buffers (0 = no limit)");
|
||||
|
||||
/* Hard limit, necessary to avoid arithmetic overflow */
|
||||
#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000)
|
||||
|
||||
static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */
|
||||
|
||||
/* Check whether it's okay to allocate more memory for a transfer */
|
||||
@ -1460,6 +1463,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
USBDEVFS_URB_ZERO_PACKET |
|
||||
USBDEVFS_URB_NO_INTERRUPT))
|
||||
return -EINVAL;
|
||||
if ((unsigned int)uurb->buffer_length >= USBFS_XFER_MAX)
|
||||
return -EINVAL;
|
||||
if (uurb->buffer_length > 0 && !uurb->buffer)
|
||||
return -EINVAL;
|
||||
if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
|
||||
@ -1571,7 +1576,11 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
totlen += isopkt[u].length;
|
||||
}
|
||||
u *= sizeof(struct usb_iso_packet_descriptor);
|
||||
uurb->buffer_length = totlen;
|
||||
if (totlen <= uurb->buffer_length)
|
||||
uurb->buffer_length = totlen;
|
||||
else
|
||||
WARN_ONCE(1, "uurb->buffer_length is too short %d vs %d",
|
||||
totlen, uurb->buffer_length);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -4838,7 +4838,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
||||
goto loop;
|
||||
|
||||
if (udev->quirks & USB_QUIRK_DELAY_INIT)
|
||||
msleep(1000);
|
||||
msleep(2000);
|
||||
|
||||
/* consecutive bus-powered hubs aren't reliable; they can
|
||||
* violate the voltage drop budget. if the new child has
|
||||
|
@ -2069,6 +2069,10 @@ int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
|
||||
elength = 1;
|
||||
goto next_desc;
|
||||
}
|
||||
if ((buflen < elength) || (elength < 3)) {
|
||||
dev_err(&intf->dev, "invalid descriptor buffer length\n");
|
||||
break;
|
||||
}
|
||||
if (buffer[1] != USB_DT_CS_INTERFACE) {
|
||||
dev_err(&intf->dev, "skipping garbage\n");
|
||||
goto next_desc;
|
||||
|
@ -177,6 +177,7 @@ static const struct of_device_id of_dwc3_simple_match[] = {
|
||||
{ .compatible = "rockchip,rk3399-dwc3" },
|
||||
{ .compatible = "xlnx,zynqmp-dwc3" },
|
||||
{ .compatible = "cavium,octeon-7130-usb-uctl" },
|
||||
{ .compatible = "sprd,sc9860-dwc3" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
|
||||
|
@ -990,6 +990,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
|
||||
req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
|
||||
|
||||
/* Now prepare one extra TRB to align transfer size */
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||
maxpacket - rem,
|
||||
@ -1015,6 +1017,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
|
||||
req->trb = &dwc->ep0_trb[dep->trb_enqueue - 1];
|
||||
|
||||
/* Now prepare one extra TRB to align transfer size */
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||
0, DWC3_TRBCTL_CONTROL_DATA,
|
||||
@ -1029,6 +1033,9 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
|
||||
req->trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@
|
||||
static void ffs_data_get(struct ffs_data *ffs);
|
||||
static void ffs_data_put(struct ffs_data *ffs);
|
||||
/* Creates new ffs_data object. */
|
||||
static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
|
||||
static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
|
||||
__attribute__((malloc));
|
||||
|
||||
/* Opened counter handling. */
|
||||
static void ffs_data_opened(struct ffs_data *ffs);
|
||||
@ -780,11 +781,12 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
struct ffs_io_data *io_data = req->context;
|
||||
struct ffs_data *ffs = io_data->ffs;
|
||||
|
||||
ENTER();
|
||||
|
||||
INIT_WORK(&io_data->work, ffs_user_copy_worker);
|
||||
schedule_work(&io_data->work);
|
||||
queue_work(ffs->io_completion_wq, &io_data->work);
|
||||
}
|
||||
|
||||
static void __ffs_epfile_read_buffer_free(struct ffs_epfile *epfile)
|
||||
@ -1500,7 +1502,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
|
||||
if (unlikely(ret < 0))
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ffs = ffs_data_new();
|
||||
ffs = ffs_data_new(dev_name);
|
||||
if (unlikely(!ffs))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ffs->file_perms = data.perms;
|
||||
@ -1610,6 +1612,7 @@ static void ffs_data_put(struct ffs_data *ffs)
|
||||
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
|
||||
waitqueue_active(&ffs->ep0req_completion.wait) ||
|
||||
waitqueue_active(&ffs->wait));
|
||||
destroy_workqueue(ffs->io_completion_wq);
|
||||
kfree(ffs->dev_name);
|
||||
kfree(ffs);
|
||||
}
|
||||
@ -1642,7 +1645,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
|
||||
ffs_data_put(ffs);
|
||||
}
|
||||
|
||||
static struct ffs_data *ffs_data_new(void)
|
||||
static struct ffs_data *ffs_data_new(const char *dev_name)
|
||||
{
|
||||
struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
|
||||
if (unlikely(!ffs))
|
||||
@ -1650,6 +1653,12 @@ static struct ffs_data *ffs_data_new(void)
|
||||
|
||||
ENTER();
|
||||
|
||||
ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
|
||||
if (!ffs->io_completion_wq) {
|
||||
kfree(ffs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
refcount_set(&ffs->ref, 1);
|
||||
atomic_set(&ffs->opened, 0);
|
||||
ffs->state = FFS_READ_DESCRIPTORS;
|
||||
|
@ -307,8 +307,6 @@ struct fsg_common {
|
||||
struct completion thread_notifier;
|
||||
struct task_struct *thread_task;
|
||||
|
||||
/* Callback functions. */
|
||||
const struct fsg_operations *ops;
|
||||
/* Gadget's private data. */
|
||||
void *private_data;
|
||||
|
||||
@ -2438,6 +2436,7 @@ static void handle_exception(struct fsg_common *common)
|
||||
static int fsg_main_thread(void *common_)
|
||||
{
|
||||
struct fsg_common *common = common_;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Allow the thread to be killed by a signal, but set the signal mask
|
||||
@ -2476,21 +2475,16 @@ static int fsg_main_thread(void *common_)
|
||||
common->thread_task = NULL;
|
||||
spin_unlock_irq(&common->lock);
|
||||
|
||||
if (!common->ops || !common->ops->thread_exits
|
||||
|| common->ops->thread_exits(common) < 0) {
|
||||
int i;
|
||||
/* Eject media from all LUNs */
|
||||
|
||||
down_write(&common->filesem);
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
|
||||
struct fsg_lun *curlun = common->luns[i];
|
||||
if (!curlun || !fsg_lun_is_open(curlun))
|
||||
continue;
|
||||
down_write(&common->filesem);
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); i++) {
|
||||
struct fsg_lun *curlun = common->luns[i];
|
||||
|
||||
if (curlun && fsg_lun_is_open(curlun))
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
up_write(&common->filesem);
|
||||
}
|
||||
up_write(&common->filesem);
|
||||
|
||||
/* Let fsg_unbind() know the thread has exited */
|
||||
complete_and_exit(&common->thread_notifier, 0);
|
||||
@ -2681,13 +2675,6 @@ void fsg_common_remove_luns(struct fsg_common *common)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
|
||||
|
||||
void fsg_common_set_ops(struct fsg_common *common,
|
||||
const struct fsg_operations *ops)
|
||||
{
|
||||
common->ops = ops;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_set_ops);
|
||||
|
||||
void fsg_common_free_buffers(struct fsg_common *common)
|
||||
{
|
||||
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
|
||||
|
@ -60,17 +60,6 @@ struct fsg_module_parameters {
|
||||
struct fsg_common;
|
||||
|
||||
/* FSF callback functions */
|
||||
struct fsg_operations {
|
||||
/*
|
||||
* Callback function to call when thread exits. If no
|
||||
* callback is set or it returns value lower then zero MSF
|
||||
* will force eject all LUNs it operates on (including those
|
||||
* marked as non-removable or with prevent_medium_removal flag
|
||||
* set).
|
||||
*/
|
||||
int (*thread_exits)(struct fsg_common *common);
|
||||
};
|
||||
|
||||
struct fsg_lun_opts {
|
||||
struct config_group group;
|
||||
struct fsg_lun *lun;
|
||||
@ -142,9 +131,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun);
|
||||
|
||||
void fsg_common_remove_luns(struct fsg_common *common);
|
||||
|
||||
void fsg_common_set_ops(struct fsg_common *common,
|
||||
const struct fsg_operations *ops);
|
||||
|
||||
int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
|
||||
unsigned int id, const char *name,
|
||||
const char **name_pfx);
|
||||
|
@ -555,6 +555,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
size_t size; /* Amount of data in a TX request. */
|
||||
size_t bytes_copied = 0;
|
||||
struct usb_request *req;
|
||||
int value;
|
||||
|
||||
DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
|
||||
|
||||
@ -634,7 +635,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
|
||||
/* here, we unlock, and only unlock, to avoid deadlock. */
|
||||
spin_unlock(&dev->lock);
|
||||
value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
|
||||
spin_lock(&dev->lock);
|
||||
if (value) {
|
||||
list_add(&req->list, &dev->tx_reqs);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mutex_unlock(&dev->lock_printer_io);
|
||||
|
@ -279,6 +279,7 @@ struct ffs_data {
|
||||
} file_perms;
|
||||
|
||||
struct eventfd_ctx *ffs_eventfd;
|
||||
struct workqueue_struct *io_completion_wq;
|
||||
bool no_disconnect;
|
||||
struct work_struct reset_work;
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <linux/aio.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
@ -116,6 +116,7 @@ enum ep0_state {
|
||||
struct dev_data {
|
||||
spinlock_t lock;
|
||||
refcount_t count;
|
||||
int udc_usage;
|
||||
enum ep0_state state; /* P: lock */
|
||||
struct usb_gadgetfs_event event [N_EVENT];
|
||||
unsigned ev_next;
|
||||
@ -513,9 +514,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
INIT_WORK(&priv->work, ep_user_copy_worker);
|
||||
schedule_work(&priv->work);
|
||||
}
|
||||
spin_unlock(&epdata->dev->lock);
|
||||
|
||||
usb_ep_free_request(ep, req);
|
||||
spin_unlock(&epdata->dev->lock);
|
||||
put_ep(epdata);
|
||||
}
|
||||
|
||||
@ -939,9 +940,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
struct usb_request *req = dev->req;
|
||||
|
||||
if ((retval = setup_req (ep, req, 0)) == 0) {
|
||||
++dev->udc_usage;
|
||||
spin_unlock_irq (&dev->lock);
|
||||
retval = usb_ep_queue (ep, req, GFP_KERNEL);
|
||||
spin_lock_irq (&dev->lock);
|
||||
--dev->udc_usage;
|
||||
}
|
||||
dev->state = STATE_DEV_CONNECTED;
|
||||
|
||||
@ -983,11 +986,14 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||
retval = -EIO;
|
||||
else {
|
||||
len = min (len, (size_t)dev->req->actual);
|
||||
// FIXME don't call this with the spinlock held ...
|
||||
++dev->udc_usage;
|
||||
spin_unlock_irq(&dev->lock);
|
||||
if (copy_to_user (buf, dev->req->buf, len))
|
||||
retval = -EFAULT;
|
||||
else
|
||||
retval = len;
|
||||
spin_lock_irq(&dev->lock);
|
||||
--dev->udc_usage;
|
||||
clean_req (dev->gadget->ep0, dev->req);
|
||||
/* NOTE userspace can't yet choose to stall */
|
||||
}
|
||||
@ -1131,6 +1137,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
retval = setup_req (dev->gadget->ep0, dev->req, len);
|
||||
if (retval == 0) {
|
||||
dev->state = STATE_DEV_CONNECTED;
|
||||
++dev->udc_usage;
|
||||
spin_unlock_irq (&dev->lock);
|
||||
if (copy_from_user (dev->req->buf, buf, len))
|
||||
retval = -EFAULT;
|
||||
@ -1142,6 +1149,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||
GFP_KERNEL);
|
||||
}
|
||||
spin_lock_irq(&dev->lock);
|
||||
--dev->udc_usage;
|
||||
if (retval < 0) {
|
||||
clean_req (dev->gadget->ep0, dev->req);
|
||||
} else
|
||||
@ -1243,9 +1251,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
|
||||
struct usb_gadget *gadget = dev->gadget;
|
||||
long ret = -ENOTTY;
|
||||
|
||||
if (gadget->ops->ioctl)
|
||||
spin_lock_irq(&dev->lock);
|
||||
if (dev->state == STATE_DEV_OPENED ||
|
||||
dev->state == STATE_DEV_UNBOUND) {
|
||||
/* Not bound to a UDC */
|
||||
} else if (gadget->ops->ioctl) {
|
||||
++dev->udc_usage;
|
||||
spin_unlock_irq(&dev->lock);
|
||||
|
||||
ret = gadget->ops->ioctl (gadget, code, value);
|
||||
|
||||
spin_lock_irq(&dev->lock);
|
||||
--dev->udc_usage;
|
||||
}
|
||||
spin_unlock_irq(&dev->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1463,10 +1483,12 @@ delegate:
|
||||
if (value < 0)
|
||||
break;
|
||||
|
||||
++dev->udc_usage;
|
||||
spin_unlock (&dev->lock);
|
||||
value = usb_ep_queue (gadget->ep0, dev->req,
|
||||
GFP_KERNEL);
|
||||
spin_lock (&dev->lock);
|
||||
--dev->udc_usage;
|
||||
if (value < 0) {
|
||||
clean_req (gadget->ep0, dev->req);
|
||||
break;
|
||||
@ -1490,8 +1512,12 @@ delegate:
|
||||
req->length = value;
|
||||
req->zero = value < w_length;
|
||||
|
||||
++dev->udc_usage;
|
||||
spin_unlock (&dev->lock);
|
||||
value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
|
||||
spin_lock(&dev->lock);
|
||||
--dev->udc_usage;
|
||||
spin_unlock(&dev->lock);
|
||||
if (value < 0) {
|
||||
DBG (dev, "ep_queue --> %d\n", value);
|
||||
req->status = 0;
|
||||
@ -1518,21 +1544,24 @@ static void destroy_ep_files (struct dev_data *dev)
|
||||
/* break link to FS */
|
||||
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
|
||||
list_del_init (&ep->epfiles);
|
||||
spin_unlock_irq (&dev->lock);
|
||||
|
||||
dentry = ep->dentry;
|
||||
ep->dentry = NULL;
|
||||
parent = d_inode(dentry->d_parent);
|
||||
|
||||
/* break link to controller */
|
||||
mutex_lock(&ep->lock);
|
||||
if (ep->state == STATE_EP_ENABLED)
|
||||
(void) usb_ep_disable (ep->ep);
|
||||
ep->state = STATE_EP_UNBOUND;
|
||||
usb_ep_free_request (ep->ep, ep->req);
|
||||
ep->ep = NULL;
|
||||
mutex_unlock(&ep->lock);
|
||||
|
||||
wake_up (&ep->wait);
|
||||
put_ep (ep);
|
||||
|
||||
spin_unlock_irq (&dev->lock);
|
||||
|
||||
/* break link to dcache */
|
||||
inode_lock(parent);
|
||||
d_delete (dentry);
|
||||
@ -1603,6 +1632,11 @@ gadgetfs_unbind (struct usb_gadget *gadget)
|
||||
|
||||
spin_lock_irq (&dev->lock);
|
||||
dev->state = STATE_DEV_UNBOUND;
|
||||
while (dev->udc_usage > 0) {
|
||||
spin_unlock_irq(&dev->lock);
|
||||
usleep_range(1000, 2000);
|
||||
spin_lock_irq(&dev->lock);
|
||||
}
|
||||
spin_unlock_irq (&dev->lock);
|
||||
|
||||
destroy_ep_files (dev);
|
||||
|
@ -107,15 +107,6 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
|
||||
|
||||
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
|
||||
|
||||
static unsigned long msg_registered;
|
||||
static void msg_cleanup(void);
|
||||
|
||||
static int msg_thread_exits(struct fsg_common *common)
|
||||
{
|
||||
msg_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msg_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *opts;
|
||||
@ -154,9 +145,6 @@ static struct usb_configuration msg_config_driver = {
|
||||
|
||||
static int msg_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
static const struct fsg_operations ops = {
|
||||
.thread_exits = msg_thread_exits,
|
||||
};
|
||||
struct fsg_opts *opts;
|
||||
struct fsg_config config;
|
||||
int status;
|
||||
@ -173,8 +161,6 @@ static int msg_bind(struct usb_composite_dev *cdev)
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
fsg_common_set_ops(opts->common, &ops);
|
||||
|
||||
status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
|
||||
if (status)
|
||||
goto fail_set_cdev;
|
||||
@ -256,18 +242,12 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
static int __init msg_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_composite_probe(&msg_driver);
|
||||
set_bit(0, &msg_registered);
|
||||
|
||||
return ret;
|
||||
return usb_composite_probe(&msg_driver);
|
||||
}
|
||||
module_init(msg_init);
|
||||
|
||||
static void msg_cleanup(void)
|
||||
static void __exit msg_cleanup(void)
|
||||
{
|
||||
if (test_and_clear_bit(0, &msg_registered))
|
||||
usb_composite_unregister(&msg_driver);
|
||||
usb_composite_unregister(&msg_driver);
|
||||
}
|
||||
module_exit(msg_cleanup);
|
||||
|
@ -273,6 +273,7 @@ config USB_SNP_CORE
|
||||
config USB_SNP_UDC_PLAT
|
||||
tristate "Synopsys USB 2.0 Device controller"
|
||||
depends on USB_GADGET && OF && HAS_DMA
|
||||
depends on EXTCON || EXTCON=n
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_SNP_CORE
|
||||
default ARCH_BCM_IPROC
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "atmel_usba_udc.h"
|
||||
#define USBA_VBUS_IRQFLAGS (IRQF_ONESHOT \
|
||||
| IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FS
|
||||
#include <linux/debugfs.h>
|
||||
@ -2361,7 +2363,7 @@ static int usba_udc_probe(struct platform_device *pdev)
|
||||
IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(&pdev->dev,
|
||||
gpio_to_irq(udc->vbus_pin), NULL,
|
||||
usba_vbus_irq_thread, IRQF_ONESHOT,
|
||||
usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,
|
||||
"atmel_usba_udc", udc);
|
||||
if (ret) {
|
||||
udc->vbus_pin = -ENODEV;
|
||||
|
@ -1320,8 +1320,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
|
||||
udc->dev.driver = &driver->driver;
|
||||
udc->gadget->dev.driver = &driver->driver;
|
||||
|
||||
if (driver->max_speed < udc->gadget->max_speed)
|
||||
usb_gadget_udc_set_speed(udc, driver->max_speed);
|
||||
usb_gadget_udc_set_speed(udc, driver->max_speed);
|
||||
|
||||
ret = driver->bind(udc->gadget, driver);
|
||||
if (ret)
|
||||
|
@ -237,6 +237,8 @@ struct dummy_hcd {
|
||||
|
||||
struct usb_device *udev;
|
||||
struct list_head urbp_list;
|
||||
struct urbp *next_frame_urbp;
|
||||
|
||||
u32 stream_en_ep;
|
||||
u8 num_stream[30 / 2];
|
||||
|
||||
@ -253,11 +255,13 @@ struct dummy {
|
||||
*/
|
||||
struct dummy_ep ep[DUMMY_ENDPOINTS];
|
||||
int address;
|
||||
int callback_usage;
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct dummy_request fifo_req;
|
||||
u8 fifo_buf[FIFO_SIZE];
|
||||
u16 devstatus;
|
||||
unsigned ints_enabled:1;
|
||||
unsigned udc_suspended:1;
|
||||
unsigned pullup:1;
|
||||
|
||||
@ -375,11 +379,10 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
|
||||
USB_PORT_STAT_CONNECTION) == 0)
|
||||
dum_hcd->port_status |=
|
||||
(USB_PORT_STAT_C_CONNECTION << 16);
|
||||
if ((dum_hcd->port_status &
|
||||
USB_PORT_STAT_ENABLE) == 1 &&
|
||||
(dum_hcd->port_status &
|
||||
USB_SS_PORT_LS_U0) == 1 &&
|
||||
dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
|
||||
if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) &&
|
||||
(dum_hcd->port_status &
|
||||
USB_PORT_STAT_LINK_STATE) == USB_SS_PORT_LS_U0 &&
|
||||
dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
|
||||
dum_hcd->active = 1;
|
||||
}
|
||||
} else {
|
||||
@ -440,18 +443,27 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
|
||||
(~dum_hcd->old_status) & dum_hcd->port_status;
|
||||
|
||||
/* Report reset and disconnect events to the driver */
|
||||
if (dum->driver && (disconnect || reset)) {
|
||||
if (dum->ints_enabled && (disconnect || reset)) {
|
||||
stop_activity(dum);
|
||||
++dum->callback_usage;
|
||||
spin_unlock(&dum->lock);
|
||||
if (reset)
|
||||
usb_gadget_udc_reset(&dum->gadget, dum->driver);
|
||||
else
|
||||
dum->driver->disconnect(&dum->gadget);
|
||||
spin_lock(&dum->lock);
|
||||
--dum->callback_usage;
|
||||
}
|
||||
} else if (dum_hcd->active != dum_hcd->old_active) {
|
||||
} else if (dum_hcd->active != dum_hcd->old_active &&
|
||||
dum->ints_enabled) {
|
||||
++dum->callback_usage;
|
||||
spin_unlock(&dum->lock);
|
||||
if (dum_hcd->old_active && dum->driver->suspend)
|
||||
dum->driver->suspend(&dum->gadget);
|
||||
else if (!dum_hcd->old_active && dum->driver->resume)
|
||||
dum->driver->resume(&dum->gadget);
|
||||
spin_lock(&dum->lock);
|
||||
--dum->callback_usage;
|
||||
}
|
||||
|
||||
dum_hcd->old_status = dum_hcd->port_status;
|
||||
@ -972,8 +984,11 @@ static int dummy_udc_start(struct usb_gadget *g,
|
||||
* can't enumerate without help from the driver we're binding.
|
||||
*/
|
||||
|
||||
spin_lock_irq(&dum->lock);
|
||||
dum->devstatus = 0;
|
||||
dum->driver = driver;
|
||||
dum->ints_enabled = 1;
|
||||
spin_unlock_irq(&dum->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -984,6 +999,16 @@ static int dummy_udc_stop(struct usb_gadget *g)
|
||||
struct dummy *dum = dum_hcd->dum;
|
||||
|
||||
spin_lock_irq(&dum->lock);
|
||||
dum->ints_enabled = 0;
|
||||
stop_activity(dum);
|
||||
|
||||
/* emulate synchronize_irq(): wait for callbacks to finish */
|
||||
while (dum->callback_usage > 0) {
|
||||
spin_unlock_irq(&dum->lock);
|
||||
usleep_range(1000, 2000);
|
||||
spin_lock_irq(&dum->lock);
|
||||
}
|
||||
|
||||
dum->driver = NULL;
|
||||
spin_unlock_irq(&dum->lock);
|
||||
|
||||
@ -1037,7 +1062,12 @@ static int dummy_udc_probe(struct platform_device *pdev)
|
||||
memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
|
||||
dum->gadget.name = gadget_name;
|
||||
dum->gadget.ops = &dummy_ops;
|
||||
dum->gadget.max_speed = USB_SPEED_SUPER;
|
||||
if (mod_data.is_super_speed)
|
||||
dum->gadget.max_speed = USB_SPEED_SUPER;
|
||||
else if (mod_data.is_high_speed)
|
||||
dum->gadget.max_speed = USB_SPEED_HIGH;
|
||||
else
|
||||
dum->gadget.max_speed = USB_SPEED_FULL;
|
||||
|
||||
dum->gadget.dev.parent = &pdev->dev;
|
||||
init_dummy_udc_hw(dum);
|
||||
@ -1246,6 +1276,8 @@ static int dummy_urb_enqueue(
|
||||
|
||||
list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
|
||||
urb->hcpriv = urbp;
|
||||
if (!dum_hcd->next_frame_urbp)
|
||||
dum_hcd->next_frame_urbp = urbp;
|
||||
if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
|
||||
urb->error_count = 1; /* mark as a new urb */
|
||||
|
||||
@ -1521,6 +1553,8 @@ static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
|
||||
if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
|
||||
dum->ss_hcd : dum->hs_hcd)))
|
||||
return NULL;
|
||||
if (!dum->ints_enabled)
|
||||
return NULL;
|
||||
if ((address & ~USB_DIR_IN) == 0)
|
||||
return &dum->ep[0];
|
||||
for (i = 1; i < DUMMY_ENDPOINTS; i++) {
|
||||
@ -1762,6 +1796,7 @@ static void dummy_timer(unsigned long _dum_hcd)
|
||||
spin_unlock_irqrestore(&dum->lock, flags);
|
||||
return;
|
||||
}
|
||||
dum_hcd->next_frame_urbp = NULL;
|
||||
|
||||
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
|
||||
if (!ep_info[i].name)
|
||||
@ -1778,6 +1813,10 @@ restart:
|
||||
int type;
|
||||
int status = -EINPROGRESS;
|
||||
|
||||
/* stop when we reach URBs queued after the timer interrupt */
|
||||
if (urbp == dum_hcd->next_frame_urbp)
|
||||
break;
|
||||
|
||||
urb = urbp->urb;
|
||||
if (urb->unlinked)
|
||||
goto return_urb;
|
||||
@ -1857,10 +1896,12 @@ restart:
|
||||
* until setup() returns; no reentrancy issues etc.
|
||||
*/
|
||||
if (value > 0) {
|
||||
++dum->callback_usage;
|
||||
spin_unlock(&dum->lock);
|
||||
value = dum->driver->setup(&dum->gadget,
|
||||
&setup);
|
||||
spin_lock(&dum->lock);
|
||||
--dum->callback_usage;
|
||||
|
||||
if (value >= 0) {
|
||||
/* no delays (max 64KB data stage) */
|
||||
@ -2561,8 +2602,6 @@ static struct hc_driver dummy_hcd = {
|
||||
.product_desc = "Dummy host controller",
|
||||
.hcd_priv_size = sizeof(struct dummy_hcd),
|
||||
|
||||
.flags = HCD_USB3 | HCD_SHARED,
|
||||
|
||||
.reset = dummy_setup,
|
||||
.start = dummy_start,
|
||||
.stop = dummy_stop,
|
||||
@ -2591,8 +2630,12 @@ static int dummy_hcd_probe(struct platform_device *pdev)
|
||||
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
|
||||
dum = *((void **)dev_get_platdata(&pdev->dev));
|
||||
|
||||
if (!mod_data.is_super_speed)
|
||||
if (mod_data.is_super_speed)
|
||||
dummy_hcd.flags = HCD_USB3 | HCD_SHARED;
|
||||
else if (mod_data.is_high_speed)
|
||||
dummy_hcd.flags = HCD_USB2;
|
||||
else
|
||||
dummy_hcd.flags = HCD_USB11;
|
||||
hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hs_hcd)
|
||||
return -ENOMEM;
|
||||
|
@ -1038,7 +1038,7 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
|
||||
usb3_ep->ep.maxpacket);
|
||||
u8 *buf = usb3_req->req.buf + usb3_req->req.actual;
|
||||
u32 tmp = 0;
|
||||
bool is_last;
|
||||
bool is_last = !len ? true : false;
|
||||
|
||||
if (usb3_wait_pipe_status(usb3_ep, PX_STA_BUFSTS) < 0)
|
||||
return -EBUSY;
|
||||
@ -1059,7 +1059,8 @@ static int usb3_write_pipe(struct renesas_usb3_ep *usb3_ep,
|
||||
usb3_write(usb3, tmp, fifo_reg);
|
||||
}
|
||||
|
||||
is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
|
||||
if (!is_last)
|
||||
is_last = usb3_is_transfer_complete(usb3_ep, usb3_req);
|
||||
/* Send the data */
|
||||
usb3_set_px_con_send(usb3_ep, len, is_last);
|
||||
|
||||
@ -1150,7 +1151,8 @@ static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep,
|
||||
usb3_set_p0_con_for_ctrl_read_data(usb3);
|
||||
} else {
|
||||
usb3_clear_bit(usb3, P0_MOD_DIR, USB3_P0_MOD);
|
||||
usb3_set_p0_con_for_ctrl_write_data(usb3);
|
||||
if (usb3_req->req.length)
|
||||
usb3_set_p0_con_for_ctrl_write_data(usb3);
|
||||
}
|
||||
|
||||
usb3_p0_xfer(usb3_ep, usb3_req);
|
||||
@ -2053,7 +2055,16 @@ static u32 usb3_calc_ramarea(int ram_size)
|
||||
static u32 usb3_calc_rammap_val(struct renesas_usb3_ep *usb3_ep,
|
||||
const struct usb_endpoint_descriptor *desc)
|
||||
{
|
||||
return usb3_ep->rammap_val | PN_RAMMAP_MPKT(usb_endpoint_maxp(desc));
|
||||
int i;
|
||||
const u32 max_packet_array[] = {8, 16, 32, 64, 512};
|
||||
u32 mpkt = PN_RAMMAP_MPKT(1024);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max_packet_array); i++) {
|
||||
if (usb_endpoint_maxp(desc) <= max_packet_array[i])
|
||||
mpkt = PN_RAMMAP_MPKT(max_packet_array[i]);
|
||||
}
|
||||
|
||||
return usb3_ep->rammap_val | mpkt;
|
||||
}
|
||||
|
||||
static int usb3_enable_pipe_n(struct renesas_usb3_ep *usb3_ep,
|
||||
|
@ -447,7 +447,7 @@ static int usb_asmedia_wait_write(struct pci_dev *pdev)
|
||||
if ((value & ASMT_CONTROL_WRITE_BIT) == 0)
|
||||
return 0;
|
||||
|
||||
usleep_range(40, 60);
|
||||
udelay(50);
|
||||
}
|
||||
|
||||
dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__);
|
||||
@ -1022,7 +1022,7 @@ EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
|
||||
*
|
||||
* Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
|
||||
* It signals to the BIOS that the OS wants control of the host controller,
|
||||
* and then waits 5 seconds for the BIOS to hand over control.
|
||||
* and then waits 1 second for the BIOS to hand over control.
|
||||
* If we timeout, assume the BIOS is broken and take control anyway.
|
||||
*/
|
||||
static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
@ -1069,9 +1069,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
|
||||
if (val & XHCI_HC_BIOS_OWNED) {
|
||||
writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
|
||||
|
||||
/* Wait for 5 seconds with 10 microsecond polling interval */
|
||||
/* Wait for 1 second with 10 microsecond polling interval */
|
||||
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
|
||||
0, 5000, 10);
|
||||
0, 1000000, 10);
|
||||
|
||||
/* Assume a buggy BIOS and take HC ownership anyway */
|
||||
if (timeout) {
|
||||
@ -1100,7 +1100,7 @@ hc_init:
|
||||
* operational or runtime registers. Wait 5 seconds and no more.
|
||||
*/
|
||||
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
|
||||
5000, 10);
|
||||
5000000, 10);
|
||||
/* Assume a buggy HC and start HC initialization anyway */
|
||||
if (timeout) {
|
||||
val = readl(op_reg_base + XHCI_STS_OFFSET);
|
||||
|
@ -112,7 +112,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
|
||||
|
||||
/* If PSI table exists, add the custom speed attributes from it */
|
||||
if (usb3_1 && xhci->usb3_rhub.psi_count) {
|
||||
u32 ssp_cap_base, bm_attrib, psi;
|
||||
u32 ssp_cap_base, bm_attrib, psi, psi_mant, psi_exp;
|
||||
int offset;
|
||||
|
||||
ssp_cap_base = USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE;
|
||||
@ -139,6 +139,15 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
|
||||
for (i = 0; i < xhci->usb3_rhub.psi_count; i++) {
|
||||
psi = xhci->usb3_rhub.psi[i];
|
||||
psi &= ~USB_SSP_SUBLINK_SPEED_RSVD;
|
||||
psi_exp = XHCI_EXT_PORT_PSIE(psi);
|
||||
psi_mant = XHCI_EXT_PORT_PSIM(psi);
|
||||
|
||||
/* Shift to Gbps and set SSP Link BIT(14) if 10Gpbs */
|
||||
for (; psi_exp < 3; psi_exp++)
|
||||
psi_mant /= 1000;
|
||||
if (psi_mant >= 10)
|
||||
psi |= BIT(14);
|
||||
|
||||
if ((psi & PLT_MASK) == PLT_SYM) {
|
||||
/* Symmetric, create SSA RX and TX from one PSI entry */
|
||||
put_unaligned_le32(psi, &buf[offset]);
|
||||
@ -1506,9 +1515,6 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
||||
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
|
||||
t2 &= ~PORT_WKDISC_E;
|
||||
}
|
||||
if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
|
||||
(hcd->speed < HCD_USB3))
|
||||
t2 &= ~PORT_WAKE_BITS;
|
||||
} else
|
||||
t2 &= ~PORT_WAKE_BITS;
|
||||
|
||||
|
@ -54,11 +54,6 @@
|
||||
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
|
||||
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
|
||||
#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
|
||||
|
||||
#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
|
||||
|
||||
static const char hcd_name[] = "xhci_hcd";
|
||||
@ -142,13 +137,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
||||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||||
|
||||
if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
|
||||
((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
|
||||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
|
||||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
|
||||
(pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
|
||||
xhci->quirks |= XHCI_U2_DISABLE_WAKE;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
||||
xhci->quirks |= XHCI_LPM_SUPPORT;
|
||||
xhci->quirks |= XHCI_INTEL_HOST;
|
||||
|
@ -178,14 +178,18 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
||||
* 2. xhci_plat is child of a device from firmware (dwc3-plat)
|
||||
* 3. xhci_plat is grandchild of a pci device (dwc3-pci)
|
||||
*/
|
||||
sysdev = &pdev->dev;
|
||||
if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node)
|
||||
sysdev = sysdev->parent;
|
||||
for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) {
|
||||
if (is_of_node(sysdev->fwnode) ||
|
||||
is_acpi_device_node(sysdev->fwnode))
|
||||
break;
|
||||
#ifdef CONFIG_PCI
|
||||
else if (sysdev->parent && sysdev->parent->parent &&
|
||||
sysdev->parent->parent->bus == &pci_bus_type)
|
||||
sysdev = sysdev->parent->parent;
|
||||
else if (sysdev->bus == &pci_bus_type)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!sysdev)
|
||||
sysdev = &pdev->dev;
|
||||
|
||||
/* Try to set 64-bit DMA first */
|
||||
if (WARN_ON(!sysdev->dma_mask))
|
||||
|
@ -1703,7 +1703,8 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
if (xhci->quirks & XHCI_MTK_HOST) {
|
||||
ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
|
||||
if (ret < 0) {
|
||||
xhci_free_endpoint_ring(xhci, virt_dev, ep_index);
|
||||
xhci_ring_free(xhci, virt_dev->eps[ep_index].new_ring);
|
||||
virt_dev->eps[ep_index].new_ring = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -735,6 +735,8 @@ struct xhci_ep_ctx {
|
||||
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
||||
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
|
||||
#define EP_HAS_LSA (1 << 15)
|
||||
/* hosts with LEC=1 use bits 31:24 as ESIT high bits. */
|
||||
#define CTX_TO_MAX_ESIT_PAYLOAD_HI(p) (((p) >> 24) & 0xff)
|
||||
|
||||
/* ep_info2 bitmasks */
|
||||
/*
|
||||
@ -1681,7 +1683,7 @@ struct xhci_bus_state {
|
||||
|
||||
static inline unsigned int hcd_index(struct usb_hcd *hcd)
|
||||
{
|
||||
if (hcd->speed == HCD_USB3)
|
||||
if (hcd->speed >= HCD_USB3)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
@ -1826,7 +1828,7 @@ struct xhci_hcd {
|
||||
/* For controller with a broken Port Disable implementation */
|
||||
#define XHCI_BROKEN_PORT_PED (1 << 25)
|
||||
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
|
||||
#define XHCI_U2_DISABLE_WAKE (1 << 27)
|
||||
/* Reserved. It was XHCI_U2_DISABLE_WAKE */
|
||||
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
|
||||
|
||||
unsigned int num_active_eps;
|
||||
@ -2540,8 +2542,8 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
|
||||
u8 lsa;
|
||||
u8 hid;
|
||||
|
||||
esit = EP_MAX_ESIT_PAYLOAD_HI(info) << 16 |
|
||||
EP_MAX_ESIT_PAYLOAD_LO(tx_info);
|
||||
esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 |
|
||||
CTX_TO_MAX_ESIT_PAYLOAD(tx_info);
|
||||
|
||||
ep_state = info & EP_STATE_MASK;
|
||||
max_pstr = info & EP_MAXPSTREAMS_MASK;
|
||||
|
@ -282,11 +282,26 @@ static void usbhsf_fifo_clear(struct usbhs_pipe *pipe,
|
||||
struct usbhs_fifo *fifo)
|
||||
{
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
int ret = 0;
|
||||
|
||||
if (!usbhs_pipe_is_dcp(pipe))
|
||||
usbhsf_fifo_barrier(priv, fifo);
|
||||
if (!usbhs_pipe_is_dcp(pipe)) {
|
||||
/*
|
||||
* This driver checks the pipe condition first to avoid -EBUSY
|
||||
* from usbhsf_fifo_barrier() with about 10 msec delay in
|
||||
* the interrupt handler if the pipe is RX direction and empty.
|
||||
*/
|
||||
if (usbhs_pipe_is_dir_in(pipe))
|
||||
ret = usbhs_pipe_is_accessible(pipe);
|
||||
if (!ret)
|
||||
ret = usbhsf_fifo_barrier(priv, fifo);
|
||||
}
|
||||
|
||||
usbhs_write(priv, fifo->ctr, BCLR);
|
||||
/*
|
||||
* if non-DCP pipe, this driver should set BCLR when
|
||||
* usbhsf_fifo_barrier() returns 0.
|
||||
*/
|
||||
if (!ret)
|
||||
usbhs_write(priv, fifo->ctr, BCLR);
|
||||
}
|
||||
|
||||
static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
|
||||
|
@ -834,13 +834,25 @@ Retry_Sense:
|
||||
if (result == USB_STOR_TRANSPORT_GOOD) {
|
||||
srb->result = SAM_STAT_GOOD;
|
||||
srb->sense_buffer[0] = 0x0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ATA-passthru commands use sense data to report
|
||||
* the command completion status, and often devices
|
||||
* return Check Condition status when nothing is
|
||||
* wrong.
|
||||
*/
|
||||
else if (srb->cmnd[0] == ATA_16 ||
|
||||
srb->cmnd[0] == ATA_12) {
|
||||
/* leave the data alone */
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was a problem, report an unspecified
|
||||
* hardware error to prevent the higher layers from
|
||||
* entering an infinite retry loop.
|
||||
*/
|
||||
} else {
|
||||
else {
|
||||
srb->result = DID_ERROR << 16;
|
||||
if ((sshdr.response_code & 0x72) == 0x72)
|
||||
srb->sense_buffer[1] = HARDWARE_ERROR;
|
||||
|
@ -9,7 +9,8 @@ static int uas_is_interface(struct usb_host_interface *intf)
|
||||
intf->desc.bInterfaceProtocol == USB_PR_UAS);
|
||||
}
|
||||
|
||||
static int uas_find_uas_alt_setting(struct usb_interface *intf)
|
||||
static struct usb_host_interface *uas_find_uas_alt_setting(
|
||||
struct usb_interface *intf)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -17,10 +18,10 @@ static int uas_find_uas_alt_setting(struct usb_interface *intf)
|
||||
struct usb_host_interface *alt = &intf->altsetting[i];
|
||||
|
||||
if (uas_is_interface(alt))
|
||||
return alt->desc.bAlternateSetting;
|
||||
return alt;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uas_find_endpoints(struct usb_host_interface *alt,
|
||||
@ -58,14 +59,14 @@ static int uas_use_uas_driver(struct usb_interface *intf,
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
unsigned long flags = id->driver_info;
|
||||
int r, alt;
|
||||
|
||||
struct usb_host_interface *alt;
|
||||
int r;
|
||||
|
||||
alt = uas_find_uas_alt_setting(intf);
|
||||
if (alt < 0)
|
||||
if (!alt)
|
||||
return 0;
|
||||
|
||||
r = uas_find_endpoints(&intf->altsetting[alt], eps);
|
||||
r = uas_find_endpoints(alt, eps);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
|
@ -873,14 +873,14 @@ MODULE_DEVICE_TABLE(usb, uas_usb_ids);
|
||||
static int uas_switch_interface(struct usb_device *udev,
|
||||
struct usb_interface *intf)
|
||||
{
|
||||
int alt;
|
||||
struct usb_host_interface *alt;
|
||||
|
||||
alt = uas_find_uas_alt_setting(intf);
|
||||
if (alt < 0)
|
||||
return alt;
|
||||
if (!alt)
|
||||
return -ENODEV;
|
||||
|
||||
return usb_set_interface(udev,
|
||||
intf->altsetting[0].desc.bInterfaceNumber, alt);
|
||||
return usb_set_interface(udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
|
||||
static int uas_configure_endpoints(struct uas_dev_info *devinfo)
|
||||
|
@ -1459,6 +1459,13 @@ UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_SANE_SENSE ),
|
||||
|
||||
/* Reported by Kris Lindgren <kris.lindgren@gmail.com> */
|
||||
UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"External",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_WP_DETECT ),
|
||||
|
||||
UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999,
|
||||
"Maxtor",
|
||||
"USB to SATA",
|
||||
|
@ -825,6 +825,8 @@ static int hwarc_probe(struct usb_interface *iface,
|
||||
|
||||
if (iface->cur_altsetting->desc.bNumEndpoints < 1)
|
||||
return -ENODEV;
|
||||
if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
|
||||
return -ENODEV;
|
||||
|
||||
result = -ENOMEM;
|
||||
uwb_rc = uwb_rc_alloc();
|
||||
|
@ -302,18 +302,22 @@ static int uwbd(void *param)
|
||||
/** Start the UWB daemon */
|
||||
void uwbd_start(struct uwb_rc *rc)
|
||||
{
|
||||
rc->uwbd.task = kthread_run(uwbd, rc, "uwbd");
|
||||
if (rc->uwbd.task == NULL)
|
||||
struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
|
||||
if (IS_ERR(task)) {
|
||||
rc->uwbd.task = NULL;
|
||||
printk(KERN_ERR "UWB: Cannot start management daemon; "
|
||||
"UWB won't work\n");
|
||||
else
|
||||
} else {
|
||||
rc->uwbd.task = task;
|
||||
rc->uwbd.pid = rc->uwbd.task->pid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop the UWB daemon and free any unprocessed events */
|
||||
void uwbd_stop(struct uwb_rc *rc)
|
||||
{
|
||||
kthread_stop(rc->uwbd.task);
|
||||
if (rc->uwbd.task)
|
||||
kthread_stop(rc->uwbd.task);
|
||||
uwbd_flush(rc);
|
||||
}
|
||||
|
||||
|
@ -780,6 +780,7 @@ struct usb_interface_assoc_descriptor {
|
||||
__u8 iFunction;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user