USB fixes for 7.2-rc5

Here are some small USB fixes and new device quirks and ids for 7.2-rc5.
 Included in here are:
   - usb storage quirk added
   - new usb serial device ids added
   - usb-serial device name leak and other bug fixes
   - small xhci driver fixes
   - normal batch of typec driver fixes for reported issues
   - usb-atm much-reported-by-syzbot fix for firmware download races
   - sysfs BOS device removal race fix
   - lots of usb gadget driver fixes for reported issues
   - other small USB driver fixes for other reported problems.
 
 All of these have been in linux-next this past week, many of them much
 longer.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCamYE0A8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yk0twCdFi0ivPtWtEzmP7lUNRCzmyT3MvoAoI7o6lJm
 E5+ID/c4mWfX/DjoPFhU
 =uUBv
 -----END PGP SIGNATURE-----

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

Pull USB fixes from Greg KH:
 "Here are some small USB fixes and new device quirks and ids:

   - usb storage quirk added

   - new usb serial device ids added

   - usb-serial device name leak and other bug fixes

   - small xhci driver fixes

   - normal batch of typec driver fixes for reported issues

   - usb-atm much-reported-by-syzbot fix for firmware download races

   - sysfs BOS device removal race fix

   - lots of usb gadget driver fixes for reported issues

   - other small USB driver fixes for other reported problems

  All of these have been in linux-next this past week, many of them much
  longer"

* tag 'usb-7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (30 commits)
  usb: typec: ucsi: Correct teardown ordering in ucsi_init() error path
  USB: serial: io_edgeport: cap received transmit credits
  USB: serial: option: add TDTECH MT5710-CN
  USB: serial: io_ti: reject oversized boot-mode firmware
  USB: serial: mxuport: validate firmware header size
  usb: atm: ueagle-atm: reject descriptors that confuse probe and disconnect
  usb: typec: ucsi: yoga_c630: Remove redundant duplicate altmode handling
  usb: typec: ucsi: Add duplicate detection to nvidia registration path
  usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware
  usb: gadget: dummy_hcd: prevent fifo_req reuse during giveback
  usb: chipidea: fix usage_count leak when autosuspend_delay is negative
  usb: core: sysfs: add lock to bos_descriptors_read()
  usb: musb: omap2430: Do not put borrowed of_node in probe
  usb: core: port: Deattach Type-C connector on component unbind
  USB: storage: add NO_ATA_1X quirk for Longmai USB Key
  USB: serial: ftdi_sio: add support for E+H FXA291
  USB: serial: keyspan_pda: fix data loss on receive throttling
  usb: gadget: printer: fix infinite loop in printer_read()
  usb: gadget: f_midi: cancel pending IN work before freeing the midi object
  usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown
  ...
This commit is contained in:
Linus Torvalds 2026-07-26 09:25:57 -07:00
commit 79ba9db003
30 changed files with 582 additions and 212 deletions

View File

@ -1250,6 +1250,7 @@ static void ci_hdrc_remove(struct platform_device *pdev)
usb_role_switch_unregister(ci->role_switch);
if (ci->supports_runtime_pm) {
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);

View File

@ -740,6 +740,8 @@ static void connector_unbind(struct device *dev, struct device *connector, void
sysfs_remove_link(&connector->kobj, dev_name(dev));
sysfs_remove_link(&dev->kobj, "connector");
if (port_dev->child)
typec_deattach(port_dev->connector, &port_dev->child->dev);
port_dev->connector = NULL;
}

View File

@ -899,10 +899,15 @@ bos_descriptors_read(struct file *filp, struct kobject *kobj,
{
struct device *dev = kobj_to_dev(kobj);
struct usb_device *udev = to_usb_device(dev);
struct usb_host_bos *bos = udev->bos;
struct usb_host_bos *bos;
struct usb_bos_descriptor *desc;
size_t desclen, n = 0;
int rc;
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
bos = udev->bos;
if (bos) {
desc = bos->desc;
desclen = le16_to_cpu(desc->wTotalLength);
@ -911,6 +916,7 @@ bos_descriptors_read(struct file *filp, struct kobject *kobj,
memcpy(buf, (void *) desc + off, n);
}
}
usb_unlock_device(udev);
return n;
}
static const BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */

View File

@ -1309,6 +1309,7 @@ static void f_midi_free(struct usb_function *f)
opts = container_of(f->fi, struct f_midi_opts, func_inst);
mutex_lock(&opts->lock);
if (!--midi->free_ref) {
cancel_work_sync(&midi->work);
kfree(midi->id);
kfifo_free(&midi->in_req_fifo);
kfree(midi);

View File

@ -1189,6 +1189,10 @@ static int ncm_unwrap_ntb(struct gether *port,
frame_max = ncm_opts->max_segment_size;
parse_ntb:
if (to_process < (int)opts->nth_size) {
INFO(port->func.config->cdev, "Packet too small for headers\n");
goto err;
}
tmp = (__le16 *)ntb_ptr;
/* dwSignature */
@ -1209,8 +1213,12 @@ static int ncm_unwrap_ntb(struct gether *port,
tmp++; /* skip wSequence */
block_len = get_ncm(&tmp, opts->block_length);
if (block_len == 0)
block_len = to_process;
/* (d)wBlockLength */
if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) {
if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max) ||
(block_len > to_process)) {
INFO(port->func.config->cdev, "Bad block length: %#X\n", block_len);
goto err;
}
@ -1273,7 +1281,7 @@ static int ncm_unwrap_ntb(struct gether *port,
index = index2;
/* wDatagramIndex[0] */
if ((index < opts->nth_size) ||
(index > block_len - opts->dpe_size)) {
(index > block_len)) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index);
goto err;
@ -1285,7 +1293,8 @@ static int ncm_unwrap_ntb(struct gether *port,
* ethernet hdr + crc or larger than max frame size
*/
if ((dg_len < 14 + crc_len) ||
(dg_len > frame_max)) {
(dg_len > frame_max) ||
(dg_len > block_len - index)) {
INFO(port->func.config->cdev,
"Bad dgram length: %#X\n", dg_len);
goto err;
@ -1310,7 +1319,7 @@ static int ncm_unwrap_ntb(struct gether *port,
dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
/* wDatagramIndex[1] */
if (index2 > block_len - opts->dpe_size) {
if (index2 > block_len) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index2);
goto err;

View File

@ -431,7 +431,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
struct printer_dev *dev = fd->private_data;
unsigned long flags;
size_t size;
size_t size, not_copied, copied;
size_t bytes_copied;
struct usb_request *req;
/* This is a pointer to the current USB rx request. */
@ -524,10 +524,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
else
size = len;
size -= copy_to_user(buf, current_rx_buf, size);
bytes_copied += size;
len -= size;
buf += size;
not_copied = copy_to_user(buf, current_rx_buf, size);
copied = size - not_copied;
bytes_copied += copied;
len -= copied;
buf += copied;
spin_lock_irqsave(&dev->lock, flags);
@ -542,6 +544,17 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if (dev->interface < 0)
goto out_disabled;
if (!copied) {
dev->current_rx_req = current_rx_req;
dev->current_rx_bytes = current_rx_bytes;
dev->current_rx_buf = current_rx_buf;
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return bytes_copied ? bytes_copied : -EFAULT;
}
size = copied;
/* If we not returning all the data left in this RX request
* buffer then adjust the amount of data left in the buffer.
* Othewise if we are done with this RX request buffer then

View File

@ -2363,31 +2363,158 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f)
return -ENOTSUPP;
}
struct guas_setup_wq {
struct work_struct work;
struct f_uas *fu;
unsigned int alt;
};
static void tcm_cleanup_old_alt(struct f_uas *fu)
{
if (fu->flags & USBG_IS_UAS)
uasp_cleanup_old_alt(fu);
else if (fu->flags & USBG_IS_BOT)
bot_cleanup_old_alt(fu);
fu->flags = 0;
}
static void tcm_delayed_set_alt_done(struct f_uas *fu)
{
unsigned long flags;
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
fu->delayed_set_alt_cancel = false;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
}
static bool tcm_delayed_set_alt_cancelled(struct f_uas *fu)
{
bool cancelled;
unsigned long flags;
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
cancelled = fu->delayed_set_alt_cancel;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
return cancelled;
}
static bool tcm_complete_delayed_status(struct f_uas *fu)
{
struct usb_composite_dev *cdev = fu->function.config->cdev;
struct usb_request *req = cdev->req;
unsigned long cdev_flags;
bool cancelled;
int ret;
spin_lock_irqsave(&cdev->lock, cdev_flags);
spin_lock(&fu->delayed_set_alt_lock);
cancelled = fu->delayed_set_alt_cancel;
if (!cancelled) {
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
fu->delayed_set_alt_cancel = false;
}
spin_unlock(&fu->delayed_set_alt_lock);
if (cancelled) {
spin_unlock_irqrestore(&cdev->lock, cdev_flags);
return false;
}
if (cdev->delayed_status == 0) {
WARN(cdev, "%s: Unexpected call\n", __func__);
} else if (--cdev->delayed_status == 0) {
req->length = 0;
req->context = cdev;
ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
if (ret == 0) {
cdev->setup_pending = true;
} else {
req->status = 0;
req->complete(cdev->gadget->ep0, req);
}
}
spin_unlock_irqrestore(&cdev->lock, cdev_flags);
return true;
}
static bool tcm_cancel_delayed_set_alt(struct f_uas *fu)
{
bool cleanup = false;
bool cancel = false;
unsigned long flags;
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
switch (fu->delayed_set_alt_state) {
case USBG_DELAYED_SET_ALT_IDLE:
cleanup = true;
break;
case USBG_DELAYED_SET_ALT_QUEUED:
case USBG_DELAYED_SET_ALT_RUNNING:
fu->delayed_set_alt_cancel = true;
cancel = true;
break;
}
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
if (cancel && cancel_work(&fu->delayed_set_alt)) {
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
if (fu->delayed_set_alt_state == USBG_DELAYED_SET_ALT_QUEUED) {
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
fu->delayed_set_alt_cancel = false;
cleanup = true;
}
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
}
return cleanup;
}
static void tcm_cancel_delayed_set_alt_sync(struct f_uas *fu)
{
unsigned long flags;
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE)
fu->delayed_set_alt_cancel = true;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
cancel_work_sync(&fu->delayed_set_alt);
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE;
fu->delayed_set_alt_cancel = false;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
}
static void tcm_delayed_set_alt(struct work_struct *wq)
{
struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
work);
struct f_uas *fu = work->fu;
int alt = work->alt;
struct f_uas *fu = container_of(wq, struct f_uas, delayed_set_alt);
unsigned long flags;
unsigned int alt;
kfree(work);
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_QUEUED) {
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
return;
}
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_RUNNING;
alt = fu->delayed_alt;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
if (fu->flags & USBG_IS_BOT)
bot_cleanup_old_alt(fu);
if (fu->flags & USBG_IS_UAS)
uasp_cleanup_old_alt(fu);
tcm_cleanup_old_alt(fu);
if (tcm_delayed_set_alt_cancelled(fu))
goto out_done;
if (alt == USB_G_ALT_INT_BBB)
bot_set_alt(fu);
else if (alt == USB_G_ALT_INT_UAS)
uasp_set_alt(fu);
usb_composite_setup_continue(fu->function.config->cdev);
if (tcm_complete_delayed_status(fu))
return;
tcm_cleanup_old_alt(fu);
out_done:
tcm_delayed_set_alt_done(fu);
}
static int tcm_get_alt(struct usb_function *f, unsigned intf)
@ -2413,15 +2540,20 @@ static int tcm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return -EOPNOTSUPP;
if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
struct guas_setup_wq *work;
unsigned long flags;
work = kmalloc_obj(*work, GFP_ATOMIC);
if (!work)
return -ENOMEM;
INIT_WORK(&work->work, tcm_delayed_set_alt);
work->fu = fu;
work->alt = alt;
schedule_work(&work->work);
spin_lock_irqsave(&fu->delayed_set_alt_lock, flags);
if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE) {
spin_unlock_irqrestore(&fu->delayed_set_alt_lock,
flags);
return -EBUSY;
}
fu->delayed_alt = alt;
fu->delayed_set_alt_cancel = false;
fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_QUEUED;
spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags);
schedule_work(&fu->delayed_set_alt);
return USB_GADGET_DELAYED_STATUS;
}
return -EOPNOTSUPP;
@ -2431,11 +2563,8 @@ static void tcm_disable(struct usb_function *f)
{
struct f_uas *fu = to_f_uas(f);
if (fu->flags & USBG_IS_UAS)
uasp_cleanup_old_alt(fu);
else if (fu->flags & USBG_IS_BOT)
bot_cleanup_old_alt(fu);
fu->flags = 0;
if (tcm_cancel_delayed_set_alt(fu))
tcm_cleanup_old_alt(fu);
}
static int tcm_setup(struct usb_function *f,
@ -2583,11 +2712,16 @@ static void tcm_free(struct usb_function *f)
{
struct f_uas *tcm = to_f_uas(f);
tcm_cancel_delayed_set_alt_sync(tcm);
kfree(tcm);
}
static void tcm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_uas *fu = to_f_uas(f);
tcm_cancel_delayed_set_alt_sync(fu);
tcm_cleanup_old_alt(fu);
usb_free_all_descriptors(f);
}
@ -2620,6 +2754,8 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi)
fu->function.disable = tcm_disable;
fu->function.free_func = tcm_free;
fu->tpg = tpg_instances[i].tpg;
INIT_WORK(&fu->delayed_set_alt, tcm_delayed_set_alt);
spin_lock_init(&fu->delayed_set_alt_lock);
hash_init(fu->stream_hash);
mutex_unlock(&tpg_instances_lock);

View File

@ -3,6 +3,7 @@
#define __TARGET_USB_GADGET_H__
#include <linux/kref.h>
#include <linux/spinlock.h>
/* #include <linux/usb/uas.h> */
#include <linux/hashtable.h>
#include <linux/usb/composite.h>
@ -29,6 +30,12 @@ enum {
#define USB_G_DEFAULT_SESSION_TAGS USBG_NUM_CMDS
enum {
USBG_DELAYED_SET_ALT_IDLE = 0,
USBG_DELAYED_SET_ALT_QUEUED,
USBG_DELAYED_SET_ALT_RUNNING,
};
struct tcm_usbg_nexus {
struct se_session *tvn_se_sess;
};
@ -132,6 +139,12 @@ struct f_uas {
#define USBG_BOT_CMD_PEND (1 << 4)
#define USBG_BOT_WEDGED (1 << 5)
struct work_struct delayed_set_alt;
spinlock_t delayed_set_alt_lock; /* protects delayed_set_alt_* */
unsigned int delayed_alt;
unsigned int delayed_set_alt_state;
bool delayed_set_alt_cancel;
struct usbg_cdb cmd[USBG_NUM_CMDS];
struct usb_ep *ep_in;
struct usb_ep *ep_out;

View File

@ -200,6 +200,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
return usb_ep_set_halt(cdev->gadget->ep0);
req->length = min_t(unsigned int, uvc->event_length, data->length);
if (req->length > sizeof(data->data))
req->length = sizeof(data->data);
req->zero = data->length < uvc->event_length;
memcpy(req->buf, data->data, req->length);

View File

@ -585,9 +585,29 @@ static int bdc_probe(struct platform_device *pdev)
static void bdc_remove(struct platform_device *pdev)
{
struct bdc *bdc;
unsigned long flags;
u32 temp;
bdc = platform_get_drvdata(pdev);
dev_dbg(bdc->dev, "%s ()\n", __func__);
/*
* Disable the device interrupt source before freeing the IRQ:
* clear BDC_GIE so the controller stops asserting interrupts,
* then free_irq drains any in-flight handler.
*/
spin_lock_irqsave(&bdc->lock, flags);
temp = bdc_readl(bdc->regs, BDC_BDCSC);
temp &= ~BDC_GIE;
bdc_writel(bdc->regs, BDC_BDCSC, temp);
spin_unlock_irqrestore(&bdc->lock, flags);
free_irq(bdc->irq, bdc);
/*
* Drain func_wake_notify after free_irq: the IRQ handler arms this
* delayed_work via bdc_sr_uspc -> handle_link_state_change ->
* schedule_delayed_work (self-rearmed in bdc_func_wake_timer), so
* the IRQ must be released first to prevent re-arm after cancel.
*/
cancel_delayed_work_sync(&bdc->func_wake_notify);
bdc_udc_exit(bdc);
bdc_hw_exit(bdc);
bdc_phy_exit(bdc);

View File

@ -530,8 +530,8 @@ int bdc_udc_init(struct bdc *bdc)
bdc->gadget.name = BRCM_BDC_NAME;
ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt,
IRQF_SHARED, BRCM_BDC_NAME, bdc);
ret = request_irq(bdc->irq, bdc_udc_interrupt, IRQF_SHARED,
BRCM_BDC_NAME, bdc);
if (ret) {
dev_err(bdc->dev,
"failed to request irq #%d %d\n",
@ -542,7 +542,7 @@ int bdc_udc_init(struct bdc *bdc)
ret = bdc_init_ep(bdc);
if (ret) {
dev_err(bdc->dev, "bdc init ep fail: %d\n", ret);
return ret;
goto err0;
}
ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);
@ -571,6 +571,7 @@ int bdc_udc_init(struct bdc *bdc)
err1:
usb_del_gadget_udc(&bdc->gadget);
err0:
free_irq(bdc->irq, bdc);
bdc_free_ep(bdc);
return ret;

View File

@ -278,6 +278,7 @@ struct dummy {
unsigned ints_enabled:1;
unsigned udc_suspended:1;
unsigned pullup:1;
unsigned fifo_req_busy:1;
/*
* HOST side support
@ -329,6 +330,26 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
/* DEVICE/GADGET SIDE UTILITY ROUTINES */
/*
* Give back a gadget request with dum->lock dropped around the callback.
* If @req is the shared fifo_req, clear fifo_req_busy afterward: the flag
* was set in dummy_queue() when the shared request was taken and must stay
* set until its completion callback has returned; list_del_init() alone
* makes the request look idle while the callback is still running.
* Caller holds dum->lock and has already done list_del_init() + status.
*/
static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep,
struct dummy_request *req)
{
bool fifo = req == &dum->fifo_req;
spin_unlock(&dum->lock);
usb_gadget_giveback_request(_ep, &req->req);
spin_lock(&dum->lock);
if (fifo)
dum->fifo_req_busy = 0;
}
/* called with spinlock held */
static void nuke(struct dummy *dum, struct dummy_ep *ep)
{
@ -339,9 +360,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep)
list_del_init(&req->queue);
req->req.status = -ESHUTDOWN;
spin_unlock(&dum->lock);
usb_gadget_giveback_request(&ep->ep, &req->req);
spin_lock(&dum->lock);
dummy_giveback(dum, &ep->ep, req);
}
}
@ -728,10 +747,11 @@ static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
/* implement an emulated single-request FIFO */
if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
list_empty(&dum->fifo_req.queue) &&
!dum->fifo_req_busy &&
list_empty(&ep->queue) &&
_req->length <= FIFO_SIZE) {
req = &dum->fifo_req;
dum->fifo_req_busy = 1;
req->req = *_req;
req->req.buf = dum->fifo_buf;
memcpy(dum->fifo_buf, _req->buf, _req->length);
@ -785,9 +805,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
dev_dbg(udc_dev(dum),
"dequeued req %p from %s, len %d buf %p\n",
req, _ep->name, _req->length, _req->buf);
spin_unlock(&dum->lock);
usb_gadget_giveback_request(_ep, _req);
spin_lock(&dum->lock);
dummy_giveback(dum, _ep, req);
}
spin_unlock_irqrestore(&dum->lock, flags);
return retval;
@ -1523,9 +1541,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
if (req->req.status != -EINPROGRESS) {
list_del_init(&req->queue);
spin_unlock(&dum->lock);
usb_gadget_giveback_request(&ep->ep, &req->req);
spin_lock(&dum->lock);
dummy_giveback(dum, &ep->ep, req);
/* requests might have been unlinked... */
rescan = 1;
@ -1910,9 +1926,7 @@ static enum hrtimer_restart dummy_timer(struct hrtimer *t)
dev_dbg(udc_dev(dum), "stale req = %p\n",
req);
spin_unlock(&dum->lock);
usb_gadget_giveback_request(&ep->ep, &req->req);
spin_lock(&dum->lock);
dummy_giveback(dum, &ep->ep, req);
ep->already_seen = 0;
goto restart;
}

View File

@ -184,7 +184,7 @@ __acquires(ep->udc->lock)
usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
if (status && (status != -ESHUTDOWN))
dev_vdbg(&udc->gadget.dev, "complete %s req %p stat %d len %u/%u\n",
dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n",
ep->ep.name, &req->req, status,
req->req.actual, req->req.length);
@ -286,7 +286,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
if (time_after(jiffies, timeout)) {
dev_err(&udc->gadget.dev, "udc reset timeout!\n");
dev_err(udc->dev, "udc reset timeout!\n");
return -ETIMEDOUT;
}
cpu_relax();
@ -309,7 +309,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
tmp &= USB_EP_LIST_ADDRESS_MASK;
fsl_writel(tmp, &dr_regs->endpointlistaddr);
dev_vdbg(&udc->gadget.dev,
dev_vdbg(udc->dev,
"vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x\n",
udc->ep_qh, (int)tmp,
fsl_readl(&dr_regs->endpointlistaddr));
@ -500,7 +500,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
break;
default:
dev_vdbg(&udc->gadget.dev, "error ep type is %d\n", ep_type);
dev_vdbg(udc->dev, "error ep type is %d\n", ep_type);
return;
}
if (zlt)
@ -613,7 +613,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
spin_unlock_irqrestore(&udc->lock, flags);
retval = 0;
dev_vdbg(&udc->gadget.dev, "enabled %s (ep%d%s) maxpacket %d\n",
dev_vdbg(udc->dev, "enabled %s (ep%d%s) maxpacket %d\n",
ep->ep.name, ep->ep.desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
max);
@ -634,13 +634,8 @@ static int fsl_ep_disable(struct usb_ep *_ep)
int ep_num;
ep = container_of(_ep, struct fsl_ep, ep);
if (!_ep || !ep->ep.desc) {
/*
* dev_vdbg(&udc->gadget.dev, "%s not enabled\n",
* _ep ? ep->ep.name : NULL);
*/
if (!_ep || !ep->ep.desc)
return -EINVAL;
}
/* disable ep on controller */
ep_num = ep_index(ep);
@ -664,7 +659,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
dev_vdbg(&udc->gadget.dev, "disabled %s OK\n", _ep->name);
dev_vdbg(udc->dev, "disabled %s OK\n", _ep->name);
return 0;
}
@ -724,9 +719,6 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
u32 temp, bitmask, tmp_stat;
/* dev_vdbg(&udc->gadget.dev, "QH addr Register 0x%8x\n", dr_regs->endpointlistaddr);
dev_vdbg(&udc->gadget.dev, "ep_qh[%d] addr is 0x%8x\n", i, (u32)&(ep->udc->ep_qh[i])); */
bitmask = ep_is_in(ep)
? (1 << (ep_index(ep) + 16))
: (1 << (ep_index(ep)));
@ -813,7 +805,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
*is_last = 0;
if ((*is_last) == 0)
dev_vdbg(&udc_controller->gadget.dev, "multi-dtd request!\n");
dev_vdbg(udc_controller->dev, "multi-dtd request!\n");
/* Fill in the transfer size; set active bit */
swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
@ -825,7 +817,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
mb();
dev_vdbg(&udc_controller->gadget.dev, "length = %d address= 0x%x\n", *length, (int)*dma);
dev_vdbg(udc_controller->dev, "length = %d address= 0x%x\n", *length, (int)*dma);
return dtd;
}
@ -876,11 +868,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
dev_vdbg(&udc->gadget.dev, "%s, bad params\n", __func__);
dev_vdbg(udc->dev, "%s, bad params\n", __func__);
return -EINVAL;
}
if (unlikely(!ep->ep.desc)) {
dev_vdbg(&udc->gadget.dev, "%s, bad ep\n", __func__);
dev_vdbg(udc->dev, "%s, bad ep\n", __func__);
return -EINVAL;
}
if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
@ -1040,7 +1032,7 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
udc->ep0_dir = 0;
}
out:
dev_vdbg(&udc->gadget.dev, "%s %s halt stat %d\n", ep->ep.name,
dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name,
value ? "set" : "clear", status);
return status;
@ -1109,7 +1101,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep)
/* Wait until flush complete */
while (fsl_readl(&dr_regs->endptflush)) {
if (time_after(jiffies, timeout)) {
dev_err(&udc_controller->gadget.dev,
dev_err(udc_controller->dev,
"ep flush timeout\n");
return;
}
@ -1182,7 +1174,7 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
udc = container_of(gadget, struct fsl_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
dev_vdbg(&gadget->dev, "VBUS %s\n", str_on_off(is_active));
dev_vdbg(udc->dev, "VBUS %s\n", str_on_off(is_active));
udc->vbus_active = (is_active != 0);
if (can_pullup(udc))
fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@ -1548,7 +1540,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
udc->ep0_state = WAIT_FOR_SETUP;
break;
case WAIT_FOR_SETUP:
dev_err(&udc->gadget.dev, "Unexpected ep0 packets\n");
dev_err(udc->dev, "Unexpected ep0 packets\n");
break;
default:
ep0stall(udc);
@ -1617,7 +1609,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
errors = hc32_to_cpu(curr_td->size_ioc_sts);
if (errors & DTD_ERROR_MASK) {
if (errors & DTD_STATUS_HALTED) {
dev_err(&udc->gadget.dev, "dTD error %08x QH=%d\n", errors, pipe);
dev_err(udc->dev, "dTD error %08x QH=%d\n", errors, pipe);
/* Clear the errors and Halt condition */
tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
tmp &= ~errors;
@ -1628,26 +1620,26 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
break;
}
if (errors & DTD_STATUS_DATA_BUFF_ERR) {
dev_vdbg(&udc->gadget.dev, "Transfer overflow\n");
dev_vdbg(udc->dev, "Transfer overflow\n");
status = -EPROTO;
break;
} else if (errors & DTD_STATUS_TRANSACTION_ERR) {
dev_vdbg(&udc->gadget.dev, "ISO error\n");
dev_vdbg(udc->dev, "ISO error\n");
status = -EILSEQ;
break;
} else
dev_err(&udc->gadget.dev,
dev_err(udc->dev,
"Unknown error has occurred (0x%x)!\n",
errors);
} else if (hc32_to_cpu(curr_td->size_ioc_sts)
& DTD_STATUS_ACTIVE) {
dev_vdbg(&udc->gadget.dev, "Request not complete\n");
dev_vdbg(udc->dev, "Request not complete\n");
status = REQ_UNCOMPLETE;
return status;
} else if (remaining_length) {
if (direction) {
dev_vdbg(&udc->gadget.dev,
dev_vdbg(udc->dev,
"Transmit dTD remaining length not zero\n");
status = -EPROTO;
break;
@ -1655,8 +1647,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
break;
}
} else {
dev_vdbg(&udc->gadget.dev,
"dTD transmitted successful\n");
dev_vdbg(udc->dev, "dTD transmitted successful\n");
}
if (j != curr_req->dtd_count - 1)
@ -1699,7 +1690,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
/* If the ep is configured */
if (!curr_ep->ep.name) {
dev_warn(&udc->gadget.dev, "Invalid EP?\n");
dev_warn(udc->dev, "Invalid EP?\n");
continue;
}
@ -1708,7 +1699,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
queue) {
status = process_ep_req(udc, i, curr_req);
dev_vdbg(&udc->gadget.dev,
dev_vdbg(udc->dev,
"status of process_ep_req= %d, ep = %d\n",
status, ep_num);
if (status == REQ_UNCOMPLETE)
@ -1829,7 +1820,7 @@ static void reset_irq(struct fsl_udc *udc)
while (fsl_readl(&dr_regs->endpointprime)) {
/* Wait until all endptprime bits cleared */
if (time_after(jiffies, timeout)) {
dev_err(&udc->gadget.dev, "Timeout for reset\n");
dev_err(udc->dev, "Timeout for reset\n");
break;
}
cpu_relax();
@ -1839,7 +1830,7 @@ static void reset_irq(struct fsl_udc *udc)
fsl_writel(0xffffffff, &dr_regs->endptflush);
if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
dev_vdbg(&udc->gadget.dev, "Bus reset\n");
dev_vdbg(udc->dev, "Bus reset\n");
/* Bus is reseting */
udc->bus_reset = 1;
/* Reset all the queues, include XD, dTD, EP queue
@ -1847,7 +1838,7 @@ static void reset_irq(struct fsl_udc *udc)
reset_queues(udc, true);
udc->usb_state = USB_STATE_DEFAULT;
} else {
dev_vdbg(&udc->gadget.dev, "Controller reset\n");
dev_vdbg(udc->dev, "Controller reset\n");
/* initialize usb hw reg except for regs for EP, not
* touch usbintr reg */
dr_controller_setup(udc);
@ -1881,7 +1872,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* Clear notification bits */
fsl_writel(irq_src, &dr_regs->usbsts);
/* dev_vdbg(&udc->gadget.dev, "irq_src [0x%8x]", irq_src); */
/* dev_vdbg(udc->dev, "irq_src [0x%8x]", irq_src); */
/* Need to resume? */
if (udc->usb_state == USB_STATE_SUSPENDED)
@ -1890,7 +1881,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* USB Interrupt */
if (irq_src & USB_STS_INT) {
dev_vdbg(&udc->gadget.dev, "Packet int\n");
dev_vdbg(udc->dev, "Packet int\n");
/* Setup package, we only support ep0 as control ep */
if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
tripwire_handler(udc, 0,
@ -1919,7 +1910,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* Reset Received */
if (irq_src & USB_STS_RESET) {
dev_vdbg(&udc->gadget.dev, "reset int\n");
dev_vdbg(udc->dev, "reset int\n");
reset_irq(udc);
status = IRQ_HANDLED;
}
@ -1931,7 +1922,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
}
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
dev_vdbg(&udc->gadget.dev, "Error IRQ %x\n", irq_src);
dev_vdbg(udc->dev, "Error IRQ %x\n", irq_src);
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -1967,7 +1958,7 @@ static int fsl_udc_start(struct usb_gadget *g,
udc_controller->transceiver->otg,
&udc_controller->gadget);
if (retval < 0) {
dev_err(&udc_controller->gadget.dev, "can't bind to transceiver\n");
dev_err(udc_controller->dev, "can't bind to transceiver\n");
udc_controller->driver = NULL;
return retval;
}
@ -2252,7 +2243,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->eps = kzalloc_objs(struct fsl_ep, udc->max_ep);
if (!udc->eps) {
dev_err(&udc->gadget.dev, "kmalloc udc endpoint status failed\n");
dev_err(udc->dev, "kmalloc udc endpoint status failed\n");
goto eps_alloc_failed;
}
@ -2267,7 +2258,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->ep_qh = dma_alloc_coherent(&pdev->dev, size,
&udc->ep_qh_dma, GFP_KERNEL);
if (!udc->ep_qh) {
dev_err(&udc->gadget.dev, "malloc QHs for udc failed\n");
dev_err(udc->dev, "malloc QHs for udc failed\n");
goto ep_queue_alloc_failed;
}
@ -2278,14 +2269,14 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
struct fsl_req, req);
if (!udc->status_req) {
dev_err(&udc->gadget.dev, "kzalloc for udc status request failed\n");
dev_err(udc->dev, "kzalloc for udc status request failed\n");
goto udc_status_alloc_failed;
}
/* allocate a small amount of memory to get valid address */
udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
if (!udc->status_req->req.buf) {
dev_err(&udc->gadget.dev, "kzalloc for udc request buffer failed\n");
dev_err(udc->dev, "kzalloc for udc request buffer failed\n");
goto udc_req_buf_alloc_failed;
}
@ -2373,6 +2364,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
if (udc_controller == NULL)
return -ENOMEM;
udc_controller->dev = &pdev->dev;
pdata = dev_get_platdata(&pdev->dev);
udc_controller->pdata = pdata;
spin_lock_init(&udc_controller->lock);
@ -2382,7 +2374,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
dev_err(&udc_controller->gadget.dev, "Can't find OTG driver!\n");
dev_err(&pdev->dev, "Can't find OTG driver!\n");
ret = -ENODEV;
goto err_kfree;
}
@ -2398,7 +2390,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
if (!request_mem_region(res->start, resource_size(res),
driver_name)) {
dev_err(&udc_controller->gadget.dev, "request mem region for %s failed\n", pdev->name);
dev_err(&pdev->dev, "failed to request mem region\n");
ret = -EBUSY;
goto err_kfree;
}
@ -2429,7 +2421,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl(&dr_regs->dccparams);
if (!(dccparams & DCCPARAMS_DC)) {
dev_err(&udc_controller->gadget.dev, "This SOC doesn't support device role\n");
dev_err(&pdev->dev, "This SOC doesn't support device role\n");
ret = -ENODEV;
goto err_exit;
}
@ -2447,14 +2439,14 @@ static int fsl_udc_probe(struct platform_device *pdev)
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller);
if (ret != 0) {
dev_err(&udc_controller->gadget.dev, "cannot request irq %d err %d\n",
dev_err(&pdev->dev, "cannot request irq %d err %d\n",
udc_controller->irq, ret);
goto err_exit;
}
/* Initialize the udc structure including QH member and other member */
if (struct_udc_setup(udc_controller, pdev)) {
dev_err(&udc_controller->gadget.dev, "Can't initialize udc data structure\n");
dev_err(&pdev->dev, "Can't initialize udc data structure\n");
ret = -ENOMEM;
goto err_free_irq;
}
@ -2474,7 +2466,6 @@ static int fsl_udc_probe(struct platform_device *pdev)
udc_controller->gadget.name = driver_name;
/* Setup gadget.dev and register with kernel */
dev_set_name(&udc_controller->gadget.dev, "gadget");
udc_controller->gadget.dev.of_node = pdev->dev.of_node;
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
@ -2548,12 +2539,6 @@ static void fsl_udc_remove(struct platform_device *pdev)
DECLARE_COMPLETION_ONSTACK(done);
if (!udc_controller) {
dev_err(&pdev->dev,
"Driver still in use but removing anyhow\n");
return;
}
udc_controller->done = &done;
usb_del_gadget_udc(&udc_controller->gadget);

View File

@ -470,6 +470,7 @@ struct fsl_ep {
#define EP_DIR_OUT 0
struct fsl_udc {
struct device *dev;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct fsl_usb2_platform_data *pdata;

View File

@ -2374,9 +2374,10 @@ static int pxa_udc_probe(struct platform_device *pdev)
struct pxa_udc *udc = &memory;
int retval = 0;
udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS);
udc->gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, GPIOD_ASIS);
if (IS_ERR(udc->gpiod))
return PTR_ERR(udc->gpiod);
return dev_err_probe(&pdev->dev, PTR_ERR(udc->gpiod),
"Couldn't find or request D+ gpio\n");
udc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(udc->regs))
@ -2395,11 +2396,6 @@ static int pxa_udc_probe(struct platform_device *pdev)
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
}
if (IS_ERR(udc->gpiod)) {
dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n",
PTR_ERR(udc->gpiod));
return PTR_ERR(udc->gpiod);
}
if (udc->gpiod)
gpiod_direction_output(udc->gpiod, 0);

View File

@ -3133,7 +3133,6 @@ int udc_probe(struct udc *dev)
/* device struct setup */
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH;

View File

@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_TRB_OVERFETCH;
xhci->dma_mask_bits = 36;
}
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&

View File

@ -5466,6 +5466,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->hci_version > 0x100)
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
xhci->dma_mask_bits = 64;
xhci->max_slots = min(HCS_MAX_SLOTS(hcs_params1), MAX_HC_SLOTS);
xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS);
/* xhci-plat or xhci-pci might have set max_interrupters already */
@ -5515,12 +5516,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
xhci->hcc_params &= ~BIT(0);
/* Set dma_mask and coherent_dma_mask to 64-bits,
* if xHC supports 64-bit addressing */
/*
* Set dma_mask and coherent_dma_mask to 64-bits if xHC supports
* 64-bit addressing, unless a controller-specific quirk callback
* limits the usable address width.
*/
if ((xhci->hcc_params & HCC_64BIT_ADDR) &&
!dma_set_mask(dev, DMA_BIT_MASK(64))) {
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
!dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) {
xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n",
xhci->dma_mask_bits);
dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits));
} else {
/*
* This is to avoid error in cases where a 32-bit USB

View File

@ -1526,6 +1526,7 @@ struct xhci_hcd {
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
u32 page_size;
unsigned int dma_mask_bits;
/* MSI-X/MSI vectors */
int nvecs;
/* optional clocks */

View File

@ -454,7 +454,6 @@ static int omap2430_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to register musb device\n");
goto err_disable_rpm;
}
of_node_put(np);
return 0;
@ -464,7 +463,6 @@ static int omap2430_probe(struct platform_device *pdev)
if (!IS_ERR(glue->control_otghs))
put_device(glue->control_otghs);
err_put_musb:
of_node_put(np);
platform_device_put(musb);
return ret;

View File

@ -1072,6 +1072,8 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) },
/* Abacus Electrics */
{ USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) },
/* Endress+Hauser AG devices */
{ USB_DEVICE(FTDI_VID, FTDI_EH_FXA291_PID) },
{ } /* Terminating entry */
};

View File

@ -313,6 +313,11 @@
#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */
#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */
/*
* Endress+Hauser AG product ids (FTDI_VID)
*/
#define FTDI_EH_FXA291_PID 0xE510
/*
* EVER Eco Pro UPS (http://www.ever.com.pl/)
*/

View File

@ -646,7 +646,8 @@ static void edge_interrupt_callback(struct urb *urb)
if (edge_port && edge_port->open) {
spin_lock_irqsave(&edge_port->ep_lock,
flags);
edge_port->txCredits += txCredits;
edge_port->txCredits = min(edge_port->txCredits + txCredits,
edge_port->maxTxCredits);
spin_unlock_irqrestore(&edge_port->ep_lock,
flags);
dev_dbg(dev, "%s - txcredits for port%d = %d\n",

View File

@ -1464,6 +1464,12 @@ static int do_boot_mode(struct edgeport_serial *serial,
/* Allocate a 15.5k buffer + 3 byte header */
buffer_size = (((1024 * 16) - 512) +
sizeof(struct ti_i2c_image_header));
if (fw->size - 4 > buffer_size) {
dev_err(dev, "%s - firmware image is too large\n",
__func__);
return -EINVAL;
}
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;

View File

@ -33,6 +33,8 @@ struct keyspan_pda_private {
struct work_struct unthrottle_work;
struct usb_serial *serial;
struct usb_serial_port *port;
bool throttled;
bool throttle_req;
};
static int keyspan_pda_write_start(struct usb_serial_port *port);
@ -148,6 +150,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
int retval;
int status = urb->status;
struct keyspan_pda_private *priv;
bool throttled = false;
unsigned long flags;
priv = usb_get_serial_port_data(port);
@ -209,16 +212,24 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
}
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&port->dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, retval);
spin_lock_irqsave(&port->lock, flags);
if (priv->throttle_req) {
priv->throttled = true;
throttled = true;
}
spin_unlock_irqrestore(&port->lock, flags);
if (!throttled) {
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&port->dev, "failed to resubmit in urb: %d\n", retval);
}
}
static void keyspan_pda_rx_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
/*
* Stop receiving characters. We just turn off the URB request, and
@ -228,16 +239,29 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty)
* send an XOFF, although it might make sense to foist that off upon
* the device too.
*/
usb_kill_urb(port->interrupt_in_urb);
spin_lock_irq(&port->lock);
priv->throttle_req = true;
spin_unlock_irq(&port->lock);
}
static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
bool throttled;
int ret;
/* just restart the receive interrupt URB */
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
spin_lock_irq(&port->lock);
throttled = priv->throttled;
priv->throttled = false;
priv->throttle_req = false;
spin_unlock_irq(&port->lock);
if (throttled) {
ret = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (ret)
dev_err(&port->dev, "failed to submit in urb: %d\n", ret);
}
}
static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
@ -577,6 +601,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
spin_lock_irq(&port->lock);
priv->tx_room = rc;
priv->throttled = false;
priv->throttle_req = false;
spin_unlock_irq(&port->lock);
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);

View File

@ -1080,6 +1080,13 @@ static int mxuport_probe(struct usb_serial *serial,
/* Use the firmware already in the device */
err = 0;
} else {
if (fw_p->size <= VER_ADDR_3) {
dev_err(&serial->interface->dev,
"Firmware %s is too short\n", buf);
err = -EINVAL;
goto out;
}
local_ver = ((fw_p->data[VER_ADDR_1] << 16) |
(fw_p->data[VER_ADDR_2] << 8) |
fw_p->data[VER_ADDR_3]);

View File

@ -2496,6 +2496,7 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */
.driver_info = RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) }, /* TDTECH MT5710-CN */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },

View File

@ -395,6 +395,13 @@ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110,
USB_SC_DEVICE, USB_PR_CB, NULL,
US_FL_MAX_SECTORS_MIN),
/* Reported by Ai Chao <aichao@kylinos.cn> */
UNUSUAL_DEV( 0x04b4, 0xb708, 0x0000, 0xffff,
"Longmai Technologies",
"USB Key",
USB_SC_SCSI, USB_PR_BULK, NULL,
US_FL_NO_ATA_1X),
/*
* Reported by Simon Levitt <simon@whattf.com>
* This entry needs Sub and Proto fields

View File

@ -529,6 +529,129 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
return ret;
}
static void ucsi_dump_duplicate_altmode(struct ucsi_connector *con,
u8 recipient, u16 svid,
u32 existing_vdo, u32 new_vdo,
int offset)
{
static const char * const recipient_names[] = {
[UCSI_RECIPIENT_CON] = "port",
[UCSI_RECIPIENT_SOP] = "partner",
[UCSI_RECIPIENT_SOP_P] = "plug",
[UCSI_RECIPIENT_SOP_PP] = "cable plug prime",
};
dev_warn(con->ucsi->dev,
"con%d: Firmware bug: duplicate %s altmode SVID 0x%04x at offset %d, ignoring but please contact the BIOS vendor to fix this issue.\n",
con->num, recipient_names[recipient], svid, offset);
if (existing_vdo != new_vdo)
dev_warn(con->ucsi->dev,
"con%d: VDO mismatch: 0x%08x vs 0x%08x\n",
con->num, existing_vdo, new_vdo);
}
/* Count altmodes in @altmodes that advertise @svid. */
static int ucsi_altmode_count_svid(struct typec_altmode **altmodes, u16 svid)
{
int count = 0;
int k;
for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
if (!altmodes[k])
break;
if (altmodes[k]->svid == svid)
count++;
}
return count;
}
/*
* Check if an altmode is a duplicate. Some firmware implementations
* incorrectly return the same altmode multiple times, causing sysfs errors.
* Returns true if the altmode should be skipped.
*
* The matching rules differ by recipient:
*
* - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug):
* Two altmodes with identical SVID and VDO are byte-for-byte duplicates
* and the second has no observable function. Drop them.
*
* - UCSI_RECIPIENT_SOP (partner):
* The typec class binds each partner altmode to a port altmode of the
* same SVID via altmode_match()/device_find_child(), which returns the
* first port altmode with a matching SVID. If the partner advertises
* more altmodes for SVID X than the port advertises, the surplus
* partner altmode(s) collapse onto an already-paired port altmode and
* trigger a "duplicate filename .../partner" sysfs error during
* typec_altmode_create_links(). Use the port-side altmode count for
* SVID X as the authoritative cap and reject any partner altmode that
* would exceed it. This preserves legitimate multi-Mode partner
* altmodes (e.g. vendor SVIDs that the port really does advertise
* twice) while filtering the firmware-generated duplicates that have
* no port counterpart.
*/
static bool ucsi_altmode_is_duplicate(struct ucsi_connector *con, u8 recipient,
const struct ucsi_altmode *alt_batch, int batch_idx,
u16 svid, u32 vdo, int offset)
{
struct typec_altmode **altmodes;
int port_count, partner_count;
int k;
/* Check for duplicates within the current batch first */
for (k = 0; k < batch_idx; k++) {
if (alt_batch[k].svid == svid && alt_batch[k].mid == vdo) {
ucsi_dump_duplicate_altmode(con, recipient, svid,
vdo, vdo, offset);
return true;
}
}
switch (recipient) {
case UCSI_RECIPIENT_SOP:
/*
* Cap partner altmodes per SVID by the port-side count:
* any further partner altmode for that SVID would alias an
* already-paired port altmode and break typec sysfs.
*/
port_count = ucsi_altmode_count_svid(con->port_altmode, svid);
partner_count = ucsi_altmode_count_svid(con->partner_altmode,
svid);
if (port_count && partner_count >= port_count) {
ucsi_dump_duplicate_altmode(con, recipient, svid,
con->partner_altmode[partner_count - 1]->vdo,
vdo, offset);
return true;
}
return false;
case UCSI_RECIPIENT_CON:
altmodes = con->port_altmode;
break;
case UCSI_RECIPIENT_SOP_P:
altmodes = con->plug_altmode;
break;
default:
return false;
}
/* CON and SOP_P: drop only exact SVID+VDO duplicates. */
for (k = 0; k < UCSI_MAX_ALTMODES; k++) {
if (!altmodes[k])
break;
if (altmodes[k]->svid != svid || altmodes[k]->vdo != vdo)
continue;
ucsi_dump_duplicate_altmode(con, recipient, svid,
altmodes[k]->vdo, vdo, offset);
return true;
}
return false;
}
static int
ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
{
@ -583,19 +706,25 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
/* now register altmodes */
for (i = 0; i < max_altmodes; i++) {
memset(&desc, 0, sizeof(desc));
if (multi_dp) {
desc.svid = updated[i].svid;
desc.vdo = updated[i].mid;
} else {
desc.svid = orig[i].svid;
desc.vdo = orig[i].mid;
}
desc.roles = TYPEC_PORT_DRD;
struct ucsi_altmode *altmode_array = multi_dp ? updated : orig;
if (!desc.svid)
if (!altmode_array[i].svid)
return 0;
/*
* Check for duplicates in current array and already
* registered altmodes. Skip if duplicate found.
*/
if (ucsi_altmode_is_duplicate(con, recipient, altmode_array, i,
altmode_array[i].svid,
altmode_array[i].mid, i))
continue;
memset(&desc, 0, sizeof(desc));
desc.svid = altmode_array[i].svid;
desc.vdo = altmode_array[i].mid;
desc.roles = TYPEC_PORT_DRD;
ret = ucsi_register_altmode(con, &desc, recipient);
if (ret)
return ret;
@ -653,6 +782,15 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
if (!alt[j].svid)
return 0;
/*
* Check for duplicates in current batch and already
* registered altmodes. Skip if duplicate found.
*/
if (ucsi_altmode_is_duplicate(con, recipient, alt, j,
alt[j].svid, alt[j].mid,
i - num + j))
continue;
memset(&desc, 0, sizeof(desc));
desc.vdo = alt[j].mid;
desc.svid = alt[j].svid;
@ -1845,6 +1983,42 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
return ret;
}
static void ucsi_unregister_port(struct ucsi_connector *con)
{
struct ucsi_work *uwork;
if (con->wq) {
mutex_lock(&con->lock);
ucsi_unregister_partner(con);
/*
* queue delayed items immediately so they can execute
* and free themselves before the wq is destroyed
*/
list_for_each_entry(uwork, &con->partner_tasks, node) {
if (cancel_delayed_work(&uwork->work))
queue_delayed_work(con->wq, &uwork->work, 0);
}
mutex_unlock(&con->lock);
destroy_workqueue(con->wq);
con->wq = NULL;
} else {
ucsi_unregister_partner(con);
}
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
ucsi_unregister_port_psy(con);
usb_power_delivery_unregister_capabilities(con->port_sink_caps);
con->port_sink_caps = NULL;
usb_power_delivery_unregister_capabilities(con->port_source_caps);
con->port_source_caps = NULL;
usb_power_delivery_unregister(con->pd);
con->pd = NULL;
typec_unregister_port(con->port);
con->port = NULL;
}
static u64 ucsi_get_supported_notifications(struct ucsi *ucsi)
{
u16 features = ucsi->cap.features;
@ -1968,25 +2142,11 @@ static int ucsi_init(struct ucsi *ucsi)
return 0;
err_unregister:
for (con = connector; con->port; con++)
ucsi_unregister_port(con);
for (i = 0; i < ucsi->cap.num_connectors; i++)
lockdep_unregister_key(&connector[i].lock_key);
for (con = connector; con->port; con++) {
if (con->wq)
destroy_workqueue(con->wq);
ucsi_unregister_partner(con);
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
ucsi_unregister_port_psy(con);
usb_power_delivery_unregister_capabilities(con->port_sink_caps);
con->port_sink_caps = NULL;
usb_power_delivery_unregister_capabilities(con->port_source_caps);
con->port_source_caps = NULL;
usb_power_delivery_unregister(con->pd);
con->pd = NULL;
typec_unregister_port(con->port);
con->port = NULL;
}
kfree(connector);
err_reset:
memset(&ucsi->cap, 0, sizeof(ucsi->cap));
@ -2214,33 +2374,7 @@ void ucsi_unregister(struct ucsi *ucsi)
for (i = 0; i < ucsi->cap.num_connectors; i++) {
cancel_work_sync(&ucsi->connector[i].work);
if (ucsi->connector[i].wq) {
struct ucsi_work *uwork;
mutex_lock(&ucsi->connector[i].lock);
/*
* queue delayed items immediately so they can execute
* and free themselves before the wq is destroyed
*/
list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
mutex_unlock(&ucsi->connector[i].lock);
destroy_workqueue(ucsi->connector[i].wq);
}
ucsi_unregister_partner(&ucsi->connector[i]);
ucsi_unregister_altmodes(&ucsi->connector[i],
UCSI_RECIPIENT_CON);
ucsi_unregister_port_psy(&ucsi->connector[i]);
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
ucsi->connector[i].port_sink_caps = NULL;
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
ucsi->connector[i].port_source_caps = NULL;
usb_power_delivery_unregister(ucsi->connector[i].pd);
ucsi->connector[i].pd = NULL;
typec_unregister_port(ucsi->connector[i].port);
ucsi_unregister_port(&ucsi->connector[i]);
lockdep_unregister_key(&ucsi->connector[i].lock_key);
}

View File

@ -139,28 +139,6 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi,
return ret;
}
static bool yoga_c630_ucsi_update_altmodes(struct ucsi *ucsi,
u8 recipient,
struct ucsi_altmode *orig,
struct ucsi_altmode *updated)
{
int i;
if (orig[0].svid == 0 || recipient != UCSI_RECIPIENT_SOP)
return false;
/* EC is nice and repeats altmodes again and again. Ignore copies. */
for (i = 1; i < UCSI_MAX_ALTMODES; i++) {
if (orig[i].svid == orig[0].svid) {
dev_dbg(ucsi->dev, "Found duplicate altmodes, starting from %d\n", i);
memset(&orig[i], 0, (UCSI_MAX_ALTMODES - i) * sizeof(*orig));
break;
}
}
return false;
}
static void yoga_c630_ucsi_update_connector(struct ucsi_connector *con)
{
if (con->num == 1)
@ -174,7 +152,6 @@ static const struct ucsi_operations yoga_c630_ucsi_ops = {
.read_message_in = yoga_c630_ucsi_read_message_in,
.sync_control = yoga_c630_ucsi_sync_control,
.async_control = yoga_c630_ucsi_async_control,
.update_altmodes = yoga_c630_ucsi_update_altmodes,
.update_connector = yoga_c630_ucsi_update_connector,
};