aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/class/cdc-acm.c1
-rw-r--r--drivers/usb/common/ulpi.c2
-rw-r--r--drivers/usb/core/hcd.c7
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/dwc2/core.c55
-rw-r--r--drivers/usb/dwc2/core.h9
-rw-r--r--drivers/usb/dwc2/hcd.c55
-rw-r--r--drivers/usb/dwc2/hcd.h5
-rw-r--r--drivers/usb/dwc2/hcd_queue.c49
-rw-r--r--drivers/usb/dwc3/core.c6
-rw-r--r--drivers/usb/dwc3/ep0.c4
-rw-r--r--drivers/usb/gadget/composite.c11
-rw-r--r--drivers/usb/gadget/configfs.c2
-rw-r--r--drivers/usb/gadget/function/f_fs.c6
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c16
-rw-r--r--drivers/usb/gadget/function/f_midi.c4
-rw-r--r--drivers/usb/gadget/udc/fotg210-udc.c3
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/udc-core.c14
-rw-r--r--drivers/usb/host/ohci-q.c7
-rw-r--r--drivers/usb/host/ohci-tmio.c2
-rw-r--r--drivers/usb/host/xhci-hub.c22
-rw-r--r--drivers/usb/host/xhci-mem.c2
-rw-r--r--drivers/usb/host/xhci-pci.c57
-rw-r--r--drivers/usb/host/xhci-ring.c3
-rw-r--r--drivers/usb/host/xhci.c3
-rw-r--r--drivers/usb/host/xhci.h1
-rw-r--r--drivers/usb/musb/musb_virthub.c4
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c3
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/mos7720.c253
-rw-r--r--drivers/usb/serial/option.c1
-rw-r--r--drivers/usb/serial/usb-serial.c1
-rw-r--r--drivers/usb/storage/unusual_devs.h23
35 files changed, 380 insertions, 257 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 519a77ba214c..b30e7423549b 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1944,6 +1944,7 @@ static void __exit acm_exit(void)
usb_deregister(&acm_driver);
tty_unregister_driver(acm_tty_driver);
put_tty_driver(acm_tty_driver);
+ idr_destroy(&acm_minors);
}
module_init(acm_init);
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index 0e6f968e93fe..01c0c0477a9e 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -242,7 +242,7 @@ static int __init ulpi_init(void)
{
return bus_register(&ulpi_bus);
}
-module_init(ulpi_init);
+subsys_initcall(ulpi_init);
static void __exit ulpi_exit(void)
{
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index be5b2074f906..cbcd0920fb51 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1022,9 +1022,12 @@ static int register_root_hub(struct usb_hcd *hcd)
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
- if (usb_dev->speed == USB_SPEED_SUPER) {
+
+ if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(usb_dev);
- if (retval < 0) {
+ if (!retval) {
+ usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
+ } else if (usb_dev->speed == USB_SPEED_SUPER) {
mutex_unlock(&usb_bus_list_lock);
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
dev_name(&usb_dev->dev), retval);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 43cb2f2e3b43..73dfa194160b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -122,7 +122,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
-static int usb_device_supports_lpm(struct usb_device *udev)
+int usb_device_supports_lpm(struct usb_device *udev)
{
/* USB 2.1 (and greater) devices indicate LPM support through
* their USB 2.0 Extended Capabilities BOS descriptor.
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 7eb1e26798e5..457255a3306a 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -65,6 +65,7 @@ extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern int usb_major_init(void);
extern void usb_major_cleanup(void);
+extern int usb_device_supports_lpm(struct usb_device *udev);
#ifdef CONFIG_PM
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index e5b546f1152e..c3cc1a78d1e2 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -72,17 +72,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Backup Host regs */
- hr = hsotg->hr_backup;
- if (!hr) {
- hr = devm_kzalloc(hsotg->dev, sizeof(*hr), GFP_KERNEL);
- if (!hr) {
- dev_err(hsotg->dev, "%s: can't allocate host regs\n",
- __func__);
- return -ENOMEM;
- }
-
- hsotg->hr_backup = hr;
- }
+ hr = &hsotg->hr_backup;
hr->hcfg = readl(hsotg->regs + HCFG);
hr->haintmsk = readl(hsotg->regs + HAINTMSK);
for (i = 0; i < hsotg->core_params->host_channels; ++i)
@@ -90,6 +80,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
hr->hprt0 = readl(hsotg->regs + HPRT0);
hr->hfir = readl(hsotg->regs + HFIR);
+ hr->valid = true;
return 0;
}
@@ -109,12 +100,13 @@ static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Restore host regs */
- hr = hsotg->hr_backup;
- if (!hr) {
+ hr = &hsotg->hr_backup;
+ if (!hr->valid) {
dev_err(hsotg->dev, "%s: no host registers to restore\n",
__func__);
return -EINVAL;
}
+ hr->valid = false;
writel(hr->hcfg, hsotg->regs + HCFG);
writel(hr->haintmsk, hsotg->regs + HAINTMSK);
@@ -152,17 +144,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Backup dev regs */
- dr = hsotg->dr_backup;
- if (!dr) {
- dr = devm_kzalloc(hsotg->dev, sizeof(*dr), GFP_KERNEL);
- if (!dr) {
- dev_err(hsotg->dev, "%s: can't allocate device regs\n",
- __func__);
- return -ENOMEM;
- }
-
- hsotg->dr_backup = dr;
- }
+ dr = &hsotg->dr_backup;
dr->dcfg = readl(hsotg->regs + DCFG);
dr->dctl = readl(hsotg->regs + DCTL);
@@ -195,7 +177,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
}
-
+ dr->valid = true;
return 0;
}
@@ -215,12 +197,13 @@ static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Restore dev regs */
- dr = hsotg->dr_backup;
- if (!dr) {
+ dr = &hsotg->dr_backup;
+ if (!dr->valid) {
dev_err(hsotg->dev, "%s: no device registers to restore\n",
__func__);
return -EINVAL;
}
+ dr->valid = false;
writel(dr->dcfg, hsotg->regs + DCFG);
writel(dr->dctl, hsotg->regs + DCTL);
@@ -268,17 +251,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
int i;
/* Backup global regs */
- gr = hsotg->gr_backup;
- if (!gr) {
- gr = devm_kzalloc(hsotg->dev, sizeof(*gr), GFP_KERNEL);
- if (!gr) {
- dev_err(hsotg->dev, "%s: can't allocate global regs\n",
- __func__);
- return -ENOMEM;
- }
-
- hsotg->gr_backup = gr;
- }
+ gr = &hsotg->gr_backup;
gr->gotgctl = readl(hsotg->regs + GOTGCTL);
gr->gintmsk = readl(hsotg->regs + GINTMSK);
@@ -291,6 +264,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
for (i = 0; i < MAX_EPS_CHANNELS; i++)
gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));
+ gr->valid = true;
return 0;
}
@@ -309,12 +283,13 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "%s\n", __func__);
/* Restore global regs */
- gr = hsotg->gr_backup;
- if (!gr) {
+ gr = &hsotg->gr_backup;
+ if (!gr->valid) {
dev_err(hsotg->dev, "%s: no global registers to restore\n",
__func__);
return -EINVAL;
}
+ gr->valid = false;
writel(0xffffffff, hsotg->regs + GINTSTS);
writel(gr->gotgctl, hsotg->regs + GOTGCTL);
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 53b8de03f102..0ed87620941b 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -492,6 +492,7 @@ struct dwc2_gregs_backup {
u32 gdfifocfg;
u32 dtxfsiz[MAX_EPS_CHANNELS];
u32 gpwrdn;
+ bool valid;
};
/**
@@ -521,6 +522,7 @@ struct dwc2_dregs_backup {
u32 doepctl[MAX_EPS_CHANNELS];
u32 doeptsiz[MAX_EPS_CHANNELS];
u32 doepdma[MAX_EPS_CHANNELS];
+ bool valid;
};
/**
@@ -538,6 +540,7 @@ struct dwc2_hregs_backup {
u32 hcintmsk[MAX_EPS_CHANNELS];
u32 hprt0;
u32 hfir;
+ bool valid;
};
/**
@@ -705,9 +708,9 @@ struct dwc2_hsotg {
struct work_struct wf_otg;
struct timer_list wkp_timer;
enum dwc2_lx_state lx_state;
- struct dwc2_gregs_backup *gr_backup;
- struct dwc2_dregs_backup *dr_backup;
- struct dwc2_hregs_backup *hr_backup;
+ struct dwc2_gregs_backup gr_backup;
+ struct dwc2_dregs_backup dr_backup;
+ struct dwc2_hregs_backup hr_backup;
struct dentry *debug_root;
struct debugfs_regset32 *regset;
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index b10377c65064..f845c41fe9e5 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -359,10 +359,9 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
/* Caller must hold driver lock */
static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
- struct dwc2_hcd_urb *urb, void **ep_handle,
- gfp_t mem_flags)
+ struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
+ struct dwc2_qtd *qtd)
{
- struct dwc2_qtd *qtd;
u32 intr_mask;
int retval;
int dev_speed;
@@ -386,18 +385,15 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
return -ENODEV;
}
- qtd = kzalloc(sizeof(*qtd), mem_flags);
if (!qtd)
- return -ENOMEM;
+ return -EINVAL;
dwc2_hcd_qtd_init(qtd, urb);
- retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
- mem_flags);
+ retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
if (retval) {
dev_err(hsotg->dev,
"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
retval);
- kfree(qtd);
return retval;
}
@@ -2445,6 +2441,9 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
u32 tflags = 0;
void *buf;
unsigned long flags;
+ struct dwc2_qh *qh;
+ bool qh_allocated = false;
+ struct dwc2_qtd *qtd;
if (dbg_urb(urb)) {
dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
@@ -2523,15 +2522,32 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
urb->iso_frame_desc[i].length);
urb->hcpriv = dwc2_urb;
+ qh = (struct dwc2_qh *) ep->hcpriv;
+ /* Create QH for the endpoint if it doesn't exist */
+ if (!qh) {
+ qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags);
+ if (!qh) {
+ retval = -ENOMEM;
+ goto fail0;
+ }
+ ep->hcpriv = qh;
+ qh_allocated = true;
+ }
+
+ qtd = kzalloc(sizeof(*qtd), mem_flags);
+ if (!qtd) {
+ retval = -ENOMEM;
+ goto fail1;
+ }
spin_lock_irqsave(&hsotg->lock, flags);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval)
- goto fail1;
+ goto fail2;
- retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
+ retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
if (retval)
- goto fail2;
+ goto fail3;
if (alloc_bandwidth) {
dwc2_allocate_bus_bandwidth(hcd,
@@ -2543,12 +2559,25 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
return 0;
-fail2:
+fail3:
dwc2_urb->priv = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
-fail1:
+fail2:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
+ kfree(qtd);
+fail1:
+ if (qh_allocated) {
+ struct dwc2_qtd *qtd2, *qtd2_tmp;
+
+ ep->hcpriv = NULL;
+ dwc2_hcd_qh_unlink(hsotg, qh);
+ /* Free each QTD in the QH's QTD list */
+ list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list,
+ qtd_list_entry)
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh);
+ dwc2_hcd_qh_free(hsotg, qh);
+ }
fail0:
kfree(dwc2_urb);
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 7b5841c40033..fc1054965552 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -463,6 +463,9 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
/* Schedule Queue Functions */
/* Implemented in hcd_queue.c */
extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
+extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb,
+ gfp_t mem_flags);
extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
@@ -471,7 +474,7 @@ extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
- struct dwc2_qh **qh, gfp_t mem_flags);
+ struct dwc2_qh *qh);
/* Unlinks and frees a QTD */
static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 9b5c36256627..3ad63d392e13 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -191,7 +191,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
*
* Return: Pointer to the newly allocated QH, or NULL on error
*/
-static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb,
gfp_t mem_flags)
{
@@ -767,57 +767,32 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
*
* @hsotg: The DWC HCD structure
* @qtd: The QTD to add
- * @qh: Out parameter to return queue head
- * @atomic_alloc: Flag to do atomic alloc if needed
+ * @qh: Queue head to add qtd to
*
* Return: 0 if successful, negative error code otherwise
*
- * Finds the correct QH to place the QTD into. If it does not find a QH, it
- * will create a new QH. If the QH to which the QTD is added is not currently
- * scheduled, it is placed into the proper schedule based on its EP type.
+ * If the QH to which the QTD is added is not currently scheduled, it is placed
+ * into the proper schedule based on its EP type.
*/
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
- struct dwc2_qh **qh, gfp_t mem_flags)
+ struct dwc2_qh *qh)
{
- struct dwc2_hcd_urb *urb = qtd->urb;
- int allocated = 0;
int retval;
- /*
- * Get the QH which holds the QTD-list to insert to. Create QH if it
- * doesn't exist.
- */
- if (*qh == NULL) {
- *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
- if (*qh == NULL)
- return -ENOMEM;
- allocated = 1;
+ if (unlikely(!qh)) {
+ dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
+ retval = -EINVAL;
+ goto fail;
}
- retval = dwc2_hcd_qh_add(hsotg, *qh);
+ retval = dwc2_hcd_qh_add(hsotg, qh);
if (retval)
goto fail;
- qtd->qh = *qh;
- list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+ qtd->qh = qh;
+ list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
return 0;
-
fail:
- if (allocated) {
- struct dwc2_qtd *qtd2, *qtd2_tmp;
- struct dwc2_qh *qh_tmp = *qh;
-
- *qh = NULL;
- dwc2_hcd_qh_unlink(hsotg, qh_tmp);
-
- /* Free each QTD in the QH's QTD list */
- list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
- qtd_list_entry)
- dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
-
- dwc2_hcd_qh_free(hsotg, qh_tmp);
- }
-
return retval;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 5c110d8e293b..ff5773c66b84 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -446,10 +446,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
/* Select the HS PHY interface */
switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
- if (!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+ if (dwc->hsphy_interface &&
+ !strncmp(dwc->hsphy_interface, "utmi", 4)) {
reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
break;
- } else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+ } else if (dwc->hsphy_interface &&
+ !strncmp(dwc->hsphy_interface, "ulpi", 4)) {
reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
} else {
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 2ef3c8d6a9db..69e769c35cf5 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -727,6 +727,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
break;
+ case USB_REQ_SET_INTERFACE:
+ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
+ dwc->start_config_issued = false;
+ /* Fall through */
default:
dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4e3447bbd097..58b4657fc721 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1758,10 +1758,13 @@ unknown:
* take such requests too, if that's ever needed: to work
* in config 0, etc.
*/
- list_for_each_entry(f, &cdev->config->functions, list)
- if (f->req_match && f->req_match(f, ctrl))
- goto try_fun_setup;
- f = NULL;
+ if (cdev->config) {
+ list_for_each_entry(f, &cdev->config->functions, list)
+ if (f->req_match && f->req_match(f, ctrl))
+ goto try_fun_setup;
+ f = NULL;
+ }
+
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 0495c94a23d7..289e20119fea 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -571,7 +571,7 @@ static struct config_group *function_make(
if (IS_ERR(fi))
return ERR_CAST(fi);
- ret = config_item_set_name(&fi->group.cg_item, name);
+ ret = config_item_set_name(&fi->group.cg_item, "%s", name);
if (ret) {
usb_put_function_instance(fi);
return ERR_PTR(ret);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 45b8c8b338df..6e7be91e6097 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -924,7 +924,8 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
kiocb->private = p;
- kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+ if (p->aio)
+ kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
res = ffs_epfile_io(kiocb->ki_filp, p);
if (res == -EIOCBQUEUED)
@@ -968,7 +969,8 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
kiocb->private = p;
- kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+ if (p->aio)
+ kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
res = ffs_epfile_io(kiocb->ki_filp, p);
if (res == -EIOCBQUEUED)
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index d2259c663996..f936268d26c6 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2786,7 +2786,7 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns)
return -EINVAL;
}
- curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+ curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
if (unlikely(!curlun))
return -ENOMEM;
@@ -2796,8 +2796,6 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns)
common->luns = curlun;
common->nluns = nluns;
- pr_info("Number of LUNs=%d\n", common->nluns);
-
return 0;
}
EXPORT_SYMBOL_GPL(fsg_common_set_nluns);
@@ -3563,14 +3561,26 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
struct fsg_opts *opts = fsg_opts_from_func_inst(fi);
struct fsg_common *common = opts->common;
struct fsg_dev *fsg;
+ unsigned nluns, i;
fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
if (unlikely(!fsg))
return ERR_PTR(-ENOMEM);
mutex_lock(&opts->lock);
+ if (!opts->refcnt) {
+ for (nluns = i = 0; i < FSG_MAX_LUNS; ++i)
+ if (common->luns[i])
+ nluns = i + 1;
+ if (!nluns)
+ pr_warn("No LUNS defined, continuing anyway\n");
+ else
+ common->nluns = nluns;
+ pr_info("Number of LUNs=%u\n", common->nluns);
+ }
opts->refcnt++;
mutex_unlock(&opts->lock);
+
fsg->function.name = FSG_DRIVER_DESC;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 6316aa5b1c49..ad50a67c1465 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1145,7 +1145,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
if (opts->id && !midi->id) {
status = -ENOMEM;
mutex_unlock(&opts->lock);
- goto kstrdup_fail;
+ goto setup_fail;
}
midi->in_ports = opts->in_ports;
midi->out_ports = opts->out_ports;
@@ -1164,8 +1164,6 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
return &midi->func;
-kstrdup_fail:
- f_midi_unregister_card(midi);
setup_fail:
for (--i; i >= 0; i--)
kfree(midi->in_port[i]);
diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c
index e547ea7f56b1..1137e3384218 100644
--- a/drivers/usb/gadget/udc/fotg210-udc.c
+++ b/drivers/usb/gadget/udc/fotg210-udc.c
@@ -1171,7 +1171,7 @@ static int fotg210_udc_probe(struct platform_device *pdev)
udc_name, fotg210);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
- goto err_irq;
+ goto err_req;
}
ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
@@ -1183,7 +1183,6 @@ static int fotg210_udc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
-err_irq:
free_irq(ires->start, fotg210);
err_req:
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index d32160d6463f..5da37c957b53 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -2167,7 +2167,7 @@ static int mv_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- udc->phy_regs = ioremap(r->start, resource_size(r));
+ udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (udc->phy_regs == NULL) {
dev_err(&pdev->dev, "failed to map phy I/O memory\n");
return -EBUSY;
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index d69c35558f68..362ee8af5fce 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -60,13 +60,15 @@ static DEFINE_MUTEX(udc_lock);
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
+ struct device *dev = gadget->dev.parent;
+
if (req->length == 0)
return 0;
if (req->num_sgs) {
int mapped;
- mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
+ mapped = dma_map_sg(dev, req->sg, req->num_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (mapped == 0) {
dev_err(&gadget->dev, "failed to map SGs\n");
@@ -75,11 +77,11 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
req->num_mapped_sgs = mapped;
} else {
- req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
+ req->dma = dma_map_single(dev, req->buf, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (dma_mapping_error(&gadget->dev, req->dma)) {
- dev_err(&gadget->dev, "failed to map buffer\n");
+ if (dma_mapping_error(dev, req->dma)) {
+ dev_err(dev, "failed to map buffer\n");
return -EFAULT;
}
}
@@ -95,12 +97,12 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
return;
if (req->num_mapped_sgs) {
- dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
+ dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0;
} else {
- dma_unmap_single(&gadget->dev, req->dma, req->length,
+ dma_unmap_single(gadget->dev.parent, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index f7d561ed3c23..d029bbe9eb36 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -981,10 +981,6 @@ rescan_all:
int completed, modified;
__hc32 *prev;
- /* Is this ED already invisible to the hardware? */
- if (ed->state == ED_IDLE)
- goto ed_idle;
-
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps and EDs with partially retired TDs
*/
@@ -1012,12 +1008,10 @@ skip_ed:
}
/* ED's now officially unlinked, hc doesn't see */
- ed->state = ED_IDLE;
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
ed->hwNextED = 0;
wmb();
ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
-ed_idle:
/* reentrancy: if we drop the schedule lock, someone might
* have modified this list. normally it's just prepending
@@ -1088,6 +1082,7 @@ rescan_this:
if (list_empty(&ed->td_list)) {
*last = ed->ed_next;
ed->ed_next = NULL;
+ ed->state = ED_IDLE;
list_del(&ed->in_use_list);
} else if (ohci->rh_state == OHCI_RH_RUNNING) {
*last = ed->ed_next;
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index e9a6eec39142..cfcfadfc94fc 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -58,7 +58,7 @@
#define CCR_PM_CKRNEN 0x0002
#define CCR_PM_USBPW1 0x0004
#define CCR_PM_USBPW2 0x0008
-#define CCR_PM_USBPW3 0x0008
+#define CCR_PM_USBPW3 0x0010
#define CCR_PM_PMEE 0x0100
#define CCR_PM_PMES 0x8000
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index e75c565feb53..78241b5550df 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -484,10 +484,13 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
u32 pls = status_reg & PORT_PLS_MASK;
/* resume state is a xHCI internal state.
- * Do not report it to usb core.
+ * Do not report it to usb core, instead, pretend to be U3,
+ * thus usb core knows it's not ready for transfer
*/
- if (pls == XDEV_RESUME)
+ if (pls == XDEV_RESUME) {
+ *status |= USB_SS_PORT_LS_U3;
return;
+ }
/* When the CAS bit is set then warm reset
* should be performed on port
@@ -588,7 +591,14 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
status |= USB_PORT_STAT_C_RESET << 16;
/* USB3.0 only */
if (hcd->speed == HCD_USB3) {
- if ((raw_port_status & PORT_PLC))
+ /* Port link change with port in resume state should not be
+ * reported to usbcore, as this is an internal state to be
+ * handled by xhci driver. Reporting PLC to usbcore may
+ * cause usbcore clearing PLC first and port change event
+ * irq won't be generated.
+ */
+ if ((raw_port_status & PORT_PLC) &&
+ (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME)
status |= USB_PORT_STAT_C_LINK_STATE << 16;
if ((raw_port_status & PORT_WRC))
status |= USB_PORT_STAT_C_BH_RESET << 16;
@@ -1120,10 +1130,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);
if (hcd->self.root_hub->do_remote_wakeup) {
- if (bus_state->resuming_ports) {
+ if (bus_state->resuming_ports || /* USB2 */
+ bus_state->port_remote_wakeup) { /* USB3 */
spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "suspend failed because "
- "a port is resuming\n");
+ xhci_dbg(xhci, "suspend failed because a port is resuming\n");
return -EBUSY;
}
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index f8336408ef07..3e442f77a2b9 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1427,10 +1427,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
return -ENOMEM;
+ virt_dev->num_rings_cached--;
virt_dev->eps[ep_index].new_ring =
virt_dev->ring_cache[virt_dev->num_rings_cached];
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
- virt_dev->num_rings_cached--;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
1, type);
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 4a4cb1d91ac8..5590eac2b22d 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -23,10 +23,15 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/acpi.h>
#include "xhci.h"
#include "xhci-trace.h"
+#define PORT2_SSIC_CONFIG_REG2 0x883c
+#define PROG_DONE (1 << 30)
+#define SSIC_PORT_UNUSED (1 << 31)
+
/* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
@@ -176,20 +181,63 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
}
/*
+ * In some Intel xHCI controllers, in order to get D3 working,
+ * through a vendor specific SSIC CONFIG register at offset 0x883c,
+ * SSIC PORT need to be marked as "unused" before putting xHCI
+ * into D3. After D3 exit, the SSIC port need to be marked as "used".
+ * Without this change, xHCI might not enter D3 state.
* Make sure PME works on some Intel xHCI controllers by writing 1 to clear
* the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
*/
-static void xhci_pme_quirk(struct xhci_hcd *xhci)
+static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
u32 val;
void __iomem *reg;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+
+ reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
+
+ /* Notify SSIC that SSIC profile programming is not done */
+ val = readl(reg) & ~PROG_DONE;
+ writel(val, reg);
+
+ /* Mark SSIC port as unused(suspend) or used(resume) */
+ val = readl(reg);
+ if (suspend)
+ val |= SSIC_PORT_UNUSED;
+ else
+ val &= ~SSIC_PORT_UNUSED;
+ writel(val, reg);
+
+ /* Notify SSIC that SSIC profile programming is done */
+ val = readl(reg) | PROG_DONE;
+ writel(val, reg);
+ readl(reg);
+ }
+
reg = (void __iomem *) xhci->cap_regs + 0x80a4;
val = readl(reg);
writel(val | BIT(28), reg);
readl(reg);
}
+#ifdef CONFIG_ACPI
+static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
+{
+ static const u8 intel_dsm_uuid[] = {
+ 0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
+ 0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
+ };
+ acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
+}
+#else
+ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+#endif /* CONFIG_ACPI */
+
/* called during probe() after chip reset completes */
static int xhci_pci_setup(struct usb_hcd *hcd)
{
@@ -263,6 +311,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
HCC_MAX_PSA(xhci->hcc_params) >= 4)
xhci->shared_hcd->can_do_streams = 1;
+ if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+ xhci_pme_acpi_rtd3_enable(dev);
+
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
pm_runtime_put_noidle(&dev->dev);
@@ -307,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
pdev->no_d3cold = true;
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
- xhci_pme_quirk(xhci);
+ xhci_pme_quirk(hcd, true);
return xhci_suspend(xhci, do_wakeup);
}
@@ -340,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
usb_enable_intel_xhci_ports(pdev);
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
- xhci_pme_quirk(xhci);
+ xhci_pme_quirk(hcd, false);
retval = xhci_resume(xhci, hibernated);
return retval;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 94416ff70810..6a8fc52aed58 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
usb_hcd_resume_root_hub(hcd);
}
+ if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+ bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7da0d6043d33..526ebc0c7e72 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3453,6 +3453,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
return -EINVAL;
}
+ if (virt_dev->tt_info)
+ old_active_eps = virt_dev->tt_info->active_eps;
+
if (virt_dev->udev != udev) {
/* If the virt_dev and the udev does not match, this virt_dev
* may belong to another udev.
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 31e46cc55807..ed2ebf647c38 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -285,6 +285,7 @@ struct xhci_op_regs {
#define XDEV_U0 (0x0 << 5)
#define XDEV_U2 (0x2 << 5)
#define XDEV_U3 (0x3 << 5)
+#define XDEV_INACTIVE (0x6 << 5)
#define XDEV_RESUME (0xf << 5)
/* true: port has power (see HCC_PPC) */
#define PORT_POWER (1 << 9)
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index 30842bc195f5..92d5f718659b 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -275,9 +275,7 @@ static int musb_has_gadget(struct musb *musb)
#ifdef CONFIG_USB_MUSB_HOST
return 1;
#else
- if (musb->port_mode == MUSB_PORT_MODE_HOST)
- return 1;
- return musb->g.dev.driver != NULL;
+ return musb->port_mode == MUSB_PORT_MODE_HOST;
#endif
}
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 8f7cb068d29b..3fcc0483a081 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -217,6 +217,9 @@ static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
{
unsigned int vbus_value;
+ if (!mxs_phy->regmap_anatop)
+ return false;
+
if (mxs_phy->port_id == 0)
regmap_read(mxs_phy->regmap_anatop,
ANADIG_USB1_VBUS_DET_STAT,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ffd739e31bfc..eac7ccaa3c85 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -187,6 +187,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */
{ USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */
{ USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */
+ { USB_DEVICE(0x2626, 0xEA60) }, /* Aruba Networks 7xxx USB Serial Console */
{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 4f70df33975a..78b4f64c6b00 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -121,26 +121,26 @@ static DEFINE_SPINLOCK(release_lock);
static const unsigned int dummy; /* for clarity in register access fns */
enum mos_regs {
- THR, /* serial port regs */
- RHR,
- IER,
- FCR,
- ISR,
- LCR,
- MCR,
- LSR,
- MSR,
- SPR,
- DLL,
- DLM,
- DPR, /* parallel port regs */
- DSR,
- DCR,
- ECR,
- SP1_REG, /* device control regs */
- SP2_REG, /* serial port 2 (7720 only) */
- PP_REG,
- SP_CONTROL_REG,
+ MOS7720_THR, /* serial port regs */
+ MOS7720_RHR,
+ MOS7720_IER,
+ MOS7720_FCR,
+ MOS7720_ISR,
+ MOS7720_LCR,
+ MOS7720_MCR,
+ MOS7720_LSR,
+ MOS7720_MSR,
+ MOS7720_SPR,
+ MOS7720_DLL,
+ MOS7720_DLM,
+ MOS7720_DPR, /* parallel port regs */
+ MOS7720_DSR,
+ MOS7720_DCR,
+ MOS7720_ECR,
+ MOS7720_SP1_REG, /* device control regs */
+ MOS7720_SP2_REG, /* serial port 2 (7720 only) */
+ MOS7720_PP_REG,
+ MOS7720_SP_CONTROL_REG,
};
/*
@@ -150,26 +150,26 @@ enum mos_regs {
static inline __u16 get_reg_index(enum mos_regs reg)
{
static const __u16 mos7715_index_lookup_table[] = {
- 0x00, /* THR */
- 0x00, /* RHR */
- 0x01, /* IER */
- 0x02, /* FCR */
- 0x02, /* ISR */
- 0x03, /* LCR */
- 0x04, /* MCR */
- 0x05, /* LSR */
- 0x06, /* MSR */
- 0x07, /* SPR */
- 0x00, /* DLL */
- 0x01, /* DLM */
- 0x00, /* DPR */
- 0x01, /* DSR */
- 0x02, /* DCR */
- 0x0a, /* ECR */
- 0x01, /* SP1_REG */
- 0x02, /* SP2_REG (7720 only) */
- 0x04, /* PP_REG (7715 only) */
- 0x08, /* SP_CONTROL_REG */
+ 0x00, /* MOS7720_THR */
+ 0x00, /* MOS7720_RHR */
+ 0x01, /* MOS7720_IER */
+ 0x02, /* MOS7720_FCR */
+ 0x02, /* MOS7720_ISR */
+ 0x03, /* MOS7720_LCR */
+ 0x04, /* MOS7720_MCR */
+ 0x05, /* MOS7720_LSR */
+ 0x06, /* MOS7720_MSR */
+ 0x07, /* MOS7720_SPR */
+ 0x00, /* MOS7720_DLL */
+ 0x01, /* MOS7720_DLM */
+ 0x00, /* MOS7720_DPR */
+ 0x01, /* MOS7720_DSR */
+ 0x02, /* MOS7720_DCR */
+ 0x0a, /* MOS7720_ECR */
+ 0x01, /* MOS7720_SP1_REG */
+ 0x02, /* MOS7720_SP2_REG (7720 only) */
+ 0x04, /* MOS7720_PP_REG (7715 only) */
+ 0x08, /* MOS7720_SP_CONTROL_REG */
};
return mos7715_index_lookup_table[reg];
}
@@ -181,10 +181,10 @@ static inline __u16 get_reg_index(enum mos_regs reg)
static inline __u16 get_reg_value(enum mos_regs reg,
unsigned int serial_portnum)
{
- if (reg >= SP1_REG) /* control reg */
+ if (reg >= MOS7720_SP1_REG) /* control reg */
return 0x0000;
- else if (reg >= DPR) /* parallel port reg (7715 only) */
+ else if (reg >= MOS7720_DPR) /* parallel port reg (7715 only) */
return 0x0100;
else /* serial port reg */
@@ -252,7 +252,8 @@ static inline int mos7715_change_mode(struct mos7715_parport *mos_parport,
enum mos7715_pp_modes mode)
{
mos_parport->shadowECR = mode;
- write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
+ mos_parport->shadowECR);
return 0;
}
@@ -486,7 +487,7 @@ static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, SPP);
- write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, (__u8)d);
parport_epilogue(pp);
}
@@ -497,7 +498,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp)
if (parport_prologue(pp) < 0)
return 0;
- read_mos_reg(mos_parport->serial, dummy, DPR, &d);
+ read_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, &d);
parport_epilogue(pp);
return d;
}
@@ -510,7 +511,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
if (parport_prologue(pp) < 0)
return;
data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
- write_mos_reg(mos_parport->serial, dummy, DCR, data);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR, data);
mos_parport->shadowDCR = data;
parport_epilogue(pp);
}
@@ -543,7 +544,8 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp,
if (parport_prologue(pp) < 0)
return 0;
mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val;
- write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+ mos_parport->shadowDCR);
dcr = mos_parport->shadowDCR & 0x0f;
parport_epilogue(pp);
return dcr;
@@ -581,7 +583,8 @@ static void parport_mos7715_data_forward(struct parport *pp)
return;
mos7715_change_mode(mos_parport, PS2);
mos_parport->shadowDCR &= ~0x20;
- write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+ mos_parport->shadowDCR);
parport_epilogue(pp);
}
@@ -593,7 +596,8 @@ static void parport_mos7715_data_reverse(struct parport *pp)
return;
mos7715_change_mode(mos_parport, PS2);
mos_parport->shadowDCR |= 0x20;
- write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+ mos_parport->shadowDCR);
parport_epilogue(pp);
}
@@ -633,8 +637,10 @@ static void parport_mos7715_restore_state(struct parport *pp,
spin_unlock(&release_lock);
return;
}
- write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR);
- write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR);
+ write_parport_reg_nonblock(mos_parport, MOS7720_DCR,
+ mos_parport->shadowDCR);
+ write_parport_reg_nonblock(mos_parport, MOS7720_ECR,
+ mos_parport->shadowECR);
spin_unlock(&release_lock);
}
@@ -714,14 +720,16 @@ static int mos7715_parport_init(struct usb_serial *serial)
init_completion(&mos_parport->syncmsg_compl);
/* cycle parallel port reset bit */
- write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80);
- write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x80);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x00);
/* initialize device registers */
mos_parport->shadowDCR = DCR_INIT_VAL;
- write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+ mos_parport->shadowDCR);
mos_parport->shadowECR = ECR_INIT_VAL;
- write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+ write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
+ mos_parport->shadowECR);
/* register with parport core */
mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE,
@@ -1033,45 +1041,49 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
/* Initialize MCS7720 -- Write Init values to corresponding Registers
*
* Register Index
- * 0 : THR/RHR
- * 1 : IER
- * 2 : FCR
- * 3 : LCR
- * 4 : MCR
- * 5 : LSR
- * 6 : MSR
- * 7 : SPR
+ * 0 : MOS7720_THR/MOS7720_RHR
+ * 1 : MOS7720_IER
+ * 2 : MOS7720_FCR
+ * 3 : MOS7720_LCR
+ * 4 : MOS7720_MCR
+ * 5 : MOS7720_LSR
+ * 6 : MOS7720_MSR
+ * 7 : MOS7720_SPR
*
* 0x08 : SP1/2 Control Reg
*/
port_number = port->port_number;
- read_mos_reg(serial, port_number, LSR, &data);
+ read_mos_reg(serial, port_number, MOS7720_LSR, &data);
dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data);
- write_mos_reg(serial, dummy, SP1_REG, 0x02);
- write_mos_reg(serial, dummy, SP2_REG, 0x02);
+ write_mos_reg(serial, dummy, MOS7720_SP1_REG, 0x02);
+ write_mos_reg(serial, dummy, MOS7720_SP2_REG, 0x02);
- write_mos_reg(serial, port_number, IER, 0x00);
- write_mos_reg(serial, port_number, FCR, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
- write_mos_reg(serial, port_number, FCR, 0xcf);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
mos7720_port->shadowLCR = 0x03;
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
mos7720_port->shadowMCR = 0x0b;
- write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+ write_mos_reg(serial, port_number, MOS7720_MCR,
+ mos7720_port->shadowMCR);
- write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00);
- read_mos_reg(serial, dummy, SP_CONTROL_REG, &data);
+ write_mos_reg(serial, port_number, MOS7720_SP_CONTROL_REG, 0x00);
+ read_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, &data);
data = data | (port->port_number + 1);
- write_mos_reg(serial, dummy, SP_CONTROL_REG, data);
+ write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, data);
mos7720_port->shadowLCR = 0x83;
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
- write_mos_reg(serial, port_number, THR, 0x0c);
- write_mos_reg(serial, port_number, IER, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_THR, 0x0c);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
mos7720_port->shadowLCR = 0x03;
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
- write_mos_reg(serial, port_number, IER, 0x0c);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
response = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (response)
@@ -1144,8 +1156,8 @@ static void mos7720_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- write_mos_reg(serial, port->port_number, MCR, 0x00);
- write_mos_reg(serial, port->port_number, IER, 0x00);
+ write_mos_reg(serial, port->port_number, MOS7720_MCR, 0x00);
+ write_mos_reg(serial, port->port_number, MOS7720_IER, 0x00);
mos7720_port->open = 0;
}
@@ -1169,7 +1181,8 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
mos7720_port->shadowLCR = data;
- write_mos_reg(serial, port->port_number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, port->port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
}
/*
@@ -1297,7 +1310,7 @@ static void mos7720_throttle(struct tty_struct *tty)
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
- write_mos_reg(port->serial, port->port_number, MCR,
+ write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
}
}
@@ -1327,7 +1340,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR |= UART_MCR_RTS;
- write_mos_reg(port->serial, port->port_number, MCR,
+ write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
}
}
@@ -1352,35 +1365,39 @@ static int set_higher_rates(struct moschip_port *mos7720_port,
dev_dbg(&port->dev, "Sending Setting Commands ..........\n");
port_number = port->port_number;
- write_mos_reg(serial, port_number, IER, 0x00);
- write_mos_reg(serial, port_number, FCR, 0x00);
- write_mos_reg(serial, port_number, FCR, 0xcf);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
mos7720_port->shadowMCR = 0x0b;
- write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
- write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_MCR,
+ mos7720_port->shadowMCR);
+ write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x00);
/***********************************************
* Set for higher rates *
***********************************************/
/* writing baud rate verbatum into uart clock field clearly not right */
if (port_number == 0)
- sp_reg = SP1_REG;
+ sp_reg = MOS7720_SP1_REG;
else
- sp_reg = SP2_REG;
+ sp_reg = MOS7720_SP2_REG;
write_mos_reg(serial, dummy, sp_reg, baud * 0x10);
- write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03);
+ write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x03);
mos7720_port->shadowMCR = 0x2b;
- write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+ write_mos_reg(serial, port_number, MOS7720_MCR,
+ mos7720_port->shadowMCR);
/***********************************************
* Set DLL/DLM
***********************************************/
mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
- write_mos_reg(serial, port_number, DLL, 0x01);
- write_mos_reg(serial, port_number, DLM, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_DLL, 0x01);
+ write_mos_reg(serial, port_number, MOS7720_DLM, 0x00);
mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
return 0;
}
@@ -1488,15 +1505,16 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
/* Enable access to divisor latch */
mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
- write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
/* Write the divisor */
- write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff));
- write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8));
+ write_mos_reg(serial, number, MOS7720_DLL, (__u8)(divisor & 0xff));
+ write_mos_reg(serial, number, MOS7720_DLM,
+ (__u8)((divisor & 0xff00) >> 8));
/* Disable access to divisor latch */
mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
- write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
return status;
}
@@ -1600,14 +1618,16 @@ static void change_port_settings(struct tty_struct *tty,
/* Disable Interrupts */
- write_mos_reg(serial, port_number, IER, 0x00);
- write_mos_reg(serial, port_number, FCR, 0x00);
- write_mos_reg(serial, port_number, FCR, 0xcf);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
+ write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
/* Send the updated LCR value to the mos7720 */
- write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, port_number, MOS7720_LCR,
+ mos7720_port->shadowLCR);
mos7720_port->shadowMCR = 0x0b;
- write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+ write_mos_reg(serial, port_number, MOS7720_MCR,
+ mos7720_port->shadowMCR);
/* set up the MCR register and send it to the mos7720 */
mos7720_port->shadowMCR = UART_MCR_OUT2;
@@ -1619,14 +1639,17 @@ static void change_port_settings(struct tty_struct *tty,
/* To set hardware flow control to the specified *
* serial port, in SP1/2_CONTROL_REG */
if (port_number)
- write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01);
+ write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
+ 0x01);
else
- write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02);
+ write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
+ 0x02);
} else
mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
- write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+ write_mos_reg(serial, port_number, MOS7720_MCR,
+ mos7720_port->shadowMCR);
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate(tty);
@@ -1639,7 +1662,7 @@ static void change_port_settings(struct tty_struct *tty,
if (baud >= 230400) {
set_higher_rates(mos7720_port, baud);
/* Enable Interrupts */
- write_mos_reg(serial, port_number, IER, 0x0c);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
return;
}
@@ -1650,7 +1673,7 @@ static void change_port_settings(struct tty_struct *tty,
if (cflag & CBAUD)
tty_encode_baud_rate(tty, baud, baud);
/* Enable Interrupts */
- write_mos_reg(serial, port_number, IER, 0x0c);
+ write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
if (port->read_urb->status != -EINPROGRESS) {
status = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -1725,7 +1748,7 @@ static int get_lsr_info(struct tty_struct *tty,
count = mos7720_chars_in_buffer(tty);
if (count == 0) {
- read_mos_reg(port->serial, port_number, LSR, &data);
+ read_mos_reg(port->serial, port_number, MOS7720_LSR, &data);
if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
== (UART_LSR_TEMT | UART_LSR_THRE)) {
dev_dbg(&port->dev, "%s -- Empty\n", __func__);
@@ -1782,7 +1805,7 @@ static int mos7720_tiocmset(struct tty_struct *tty,
mcr &= ~UART_MCR_LOOP;
mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->port_number, MCR,
+ write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
return 0;
@@ -1827,7 +1850,7 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
}
mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->port_number, MCR,
+ write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
mos7720_port->shadowMCR);
return 0;
@@ -1942,7 +1965,7 @@ static int mos7720_startup(struct usb_serial *serial)
}
#endif
/* LSR For Port 1 */
- read_mos_reg(serial, 0, LSR, &data);
+ read_mos_reg(serial, 0, MOS7720_LSR, &data);
dev_dbg(&dev->dev, "LSR:%x\n", data);
return 0;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f0c0c53359ad..19b85ee98a72 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1765,6 +1765,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+ { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */
{ USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
{ USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
{ } /* Terminating entry */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 529066bbc7e8..46f1f13b41f1 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1306,6 +1306,7 @@ static void __exit usb_serial_exit(void)
tty_unregister_driver(usb_serial_tty_driver);
put_tty_driver(usb_serial_tty_driver);
bus_unregister(&usb_serial_bus_type);
+ idr_destroy(&serial_minors);
}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index caf188800c67..6b2479123de7 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2065,6 +2065,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_READ_DISC_INFO ),
+/* Reported by Oliver Neukum <oneukum@suse.com>
+ * This device morphes spontaneously into another device if the access
+ * pattern of Windows isn't followed. Thus writable media would be dirty
+ * if the initial instance is used. So the device is limited to its
+ * virtual CD.
+ * And yes, the concept that BCD goes up to 9 is not heeded */
+UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff,
+ "ZTE,Incorporated",
+ "ZTE WCDMA Technologies MSM",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
+
/* Reported by Sven Geggus <sven-usbst@geggus.net>
* This encrypted pen drive returns bogus data for the initial READ(10).
*/
@@ -2074,6 +2086,17 @@ UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_INITIAL_READ10 ),
+/* Reported by Hans de Goede <hdegoede@redhat.com>
+ * These are mini projectors using USB for both power and video data transport
+ * The usb-storage interface is a virtual windows driver CD, which the gm12u320
+ * driver automatically converts into framebuffer & kms dri device nodes.
+ */
+UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff,
+ "Grain-media Technology Corp.",
+ "USB3.0 Device GM12U320",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+
/* Patch by Richard Schütz <r.schtz@t-online.de>
* This external hard drive enclosure uses a JMicron chip which
* needs the US_FL_IGNORE_RESIDUE flag to work properly. */