summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/atm/ueagle-atm.c94
-rw-r--r--drivers/usb/dwc3/core.c20
-rw-r--r--drivers/usb/dwc3/core.h4
-rw-r--r--drivers/usb/dwc3/ulpi.c25
-rw-r--r--drivers/usb/gadget/function/f_fs.c89
-rw-r--r--drivers/usb/host/max3421-hcd.c8
6 files changed, 139 insertions, 101 deletions
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index cd0f7b4bd82a..a943a5257a59 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -50,12 +50,6 @@
"[ueagle-atm vdbg] " format, ##args); \
} while (0)
-#define uea_enters(usb_dev) \
- uea_vdbg(usb_dev, "entering %s\n" , __func__)
-
-#define uea_leaves(usb_dev) \
- uea_vdbg(usb_dev, "leaving %s\n" , __func__)
-
#define uea_err(usb_dev, format, args...) \
dev_err(&(usb_dev)->dev , "[UEAGLE-ATM] " format , ##args)
@@ -599,13 +593,14 @@ static int uea_send_modem_cmd(struct usb_device *usb,
static void uea_upload_pre_firmware(const struct firmware *fw_entry,
void *context)
{
- struct usb_device *usb = context;
+ struct usb_interface *intf = context;
+ struct usb_device *usb = interface_to_usbdev(intf);
+ struct completion *fw_done = usb_get_intfdata(intf);
const u8 *pfw;
u8 value;
u32 crc = 0;
int ret, size;
- uea_enters(usb);
if (!fw_entry) {
uea_err(usb, "firmware is not available\n");
goto err;
@@ -669,18 +664,18 @@ err_fw_corrupted:
uea_err(usb, "firmware is corrupted\n");
err:
release_firmware(fw_entry);
- uea_leaves(usb);
+ complete(fw_done);
}
/*
* uea_load_firmware - Load usb firmware for pre-firmware devices.
*/
-static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
+static int uea_load_firmware(struct usb_interface *intf, unsigned int ver)
{
int ret;
char *fw_name = EAGLE_FIRMWARE;
+ struct usb_device *usb = interface_to_usbdev(intf);
- uea_enters(usb);
uea_info(usb, "pre-firmware device, uploading firmware\n");
switch (ver) {
@@ -702,14 +697,13 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev,
- GFP_KERNEL, usb,
+ GFP_KERNEL, intf,
uea_upload_pre_firmware);
if (ret)
uea_err(usb, "firmware %s is not available\n", fw_name);
else
uea_info(usb, "loading firmware %s\n", fw_name);
- uea_leaves(usb);
return ret;
}
@@ -1136,7 +1130,6 @@ static int uea_cmv_e1(struct uea_softc *sc,
struct cmv_e1 cmv;
int ret;
- uea_enters(INS_TO_USBDEV(sc));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
"offset : 0x%04x, data : 0x%08x\n",
E1_FUNCTION_TYPE(function),
@@ -1163,9 +1156,8 @@ static int uea_cmv_e1(struct uea_softc *sc,
sizeof(cmv), &cmv);
if (ret < 0)
return ret;
- ret = wait_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
- return ret;
+
+ return wait_cmv_ack(sc);
}
static int uea_cmv_e4(struct uea_softc *sc,
@@ -1174,7 +1166,6 @@ static int uea_cmv_e4(struct uea_softc *sc,
struct cmv_e4 cmv;
int ret;
- uea_enters(INS_TO_USBDEV(sc));
memset(&cmv, 0, sizeof(cmv));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
@@ -1198,9 +1189,8 @@ static int uea_cmv_e4(struct uea_softc *sc,
sizeof(cmv), &cmv);
if (ret < 0)
return ret;
- ret = wait_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
- return ret;
+
+ return wait_cmv_ack(sc);
}
static inline int uea_read_cmv_e1(struct uea_softc *sc,
@@ -1294,7 +1284,6 @@ static int uea_stat_e1(struct uea_softc *sc)
u32 data;
int ret;
- uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
@@ -1437,7 +1426,6 @@ static int uea_stat_e4(struct uea_softc *sc)
u32 tmp_arr[2];
int ret;
- uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
/* XXX only need to be done before operationnal... */
@@ -1804,7 +1792,6 @@ static int uea_start_reset(struct uea_softc *sc)
u16 zero = 0; /* ;-) */
int ret;
- uea_enters(INS_TO_USBDEV(sc));
uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
/* mask interrupt */
@@ -1872,7 +1859,6 @@ static int uea_start_reset(struct uea_softc *sc)
return ret;
sc->reset = 0;
- uea_leaves(INS_TO_USBDEV(sc));
return ret;
}
@@ -1888,7 +1874,6 @@ static int uea_kthread(void *data)
int ret = -EAGAIN;
set_freezable();
- uea_enters(INS_TO_USBDEV(sc));
while (!kthread_should_stop()) {
if (ret < 0 || sc->reset)
ret = uea_start_reset(sc);
@@ -1897,7 +1882,7 @@ static int uea_kthread(void *data)
if (ret != -EAGAIN)
uea_wait(sc, 0, msecs_to_jiffies(1000));
}
- uea_leaves(INS_TO_USBDEV(sc));
+
return ret;
}
@@ -1910,8 +1895,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
u8 value;
char *fw_name = FPGA930_FIRMWARE;
- uea_enters(INS_TO_USBDEV(sc));
-
ret = request_firmware(&fw_entry, fw_name, &sc->usb_dev->dev);
if (ret) {
uea_err(INS_TO_USBDEV(sc), "firmware %s is not available\n",
@@ -1955,7 +1938,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
err1:
release_firmware(fw_entry);
err0:
- uea_leaves(INS_TO_USBDEV(sc));
return ret;
}
@@ -1965,7 +1947,6 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
- uea_enters(INS_TO_USBDEV(sc));
if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
goto bad1;
@@ -1989,7 +1970,6 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE,
E1_MODEMREADY)) {
wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
return;
}
@@ -2003,7 +1983,6 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
sc->data = sc->data << 16 | sc->data >> 16;
wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
return;
bad2:
@@ -2011,14 +1990,12 @@ bad2:
"Function : %d, Subfunction : %d\n",
E1_FUNCTION_TYPE(cmv->bFunction),
E1_FUNCTION_SUBTYPE(cmv->bFunction));
- uea_leaves(INS_TO_USBDEV(sc));
return;
bad1:
uea_err(INS_TO_USBDEV(sc), "invalid cmv received, "
"wPreamble %d, bDirection %d\n",
le16_to_cpu(cmv->wPreamble), cmv->bDirection);
- uea_leaves(INS_TO_USBDEV(sc));
}
/* The modem send us an ack. First with check if it right */
@@ -2027,7 +2004,6 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
- uea_enters(INS_TO_USBDEV(sc));
uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
@@ -2039,7 +2015,6 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE,
E4_MODEMREADY, 1)) {
wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
return;
}
@@ -2052,7 +2027,6 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
sc->data = be32_to_cpu(cmv->dwData[0]);
sc->data1 = be32_to_cpu(cmv->dwData[1]);
wake_up_cmv_ack(sc);
- uea_leaves(INS_TO_USBDEV(sc));
return;
bad2:
@@ -2060,7 +2034,6 @@ bad2:
"Function : %d, Subfunction : %d\n",
E4_FUNCTION_TYPE(cmv->wFunction),
E4_FUNCTION_SUBTYPE(cmv->wFunction));
- uea_leaves(INS_TO_USBDEV(sc));
return;
}
@@ -2088,8 +2061,6 @@ static void uea_intr(struct urb *urb)
struct intr_pkt *intr = urb->transfer_buffer;
int status = urb->status;
- uea_enters(INS_TO_USBDEV(sc));
-
if (unlikely(status < 0)) {
uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
status);
@@ -2129,8 +2100,6 @@ static int uea_boot(struct uea_softc *sc, struct usb_interface *intf)
int ret = -ENOMEM;
int size;
- uea_enters(INS_TO_USBDEV(sc));
-
if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
size = E4_INTR_PKT_SIZE;
sc->dispatch_cmv = uea_dispatch_cmv_e4;
@@ -2187,7 +2156,6 @@ static int uea_boot(struct uea_softc *sc, struct usb_interface *intf)
goto err2;
}
- uea_leaves(INS_TO_USBDEV(sc));
return 0;
err2:
@@ -2197,7 +2165,6 @@ err1:
sc->urb_int = NULL;
kfree(intr);
err0:
- uea_leaves(INS_TO_USBDEV(sc));
return ret;
}
@@ -2207,7 +2174,7 @@ err0:
static void uea_stop(struct uea_softc *sc)
{
int ret;
- uea_enters(INS_TO_USBDEV(sc));
+
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
@@ -2221,7 +2188,6 @@ static void uea_stop(struct uea_softc *sc)
flush_work(&sc->task);
release_firmware(sc->dsp_firm);
- uea_leaves(INS_TO_USBDEV(sc));
}
/* syfs interface */
@@ -2494,8 +2460,6 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
unsigned int alt;
- uea_enters(usb);
-
/* interface 0 is for firmware/monitoring */
if (ifnum != UEA_INTR_IFACE_NO)
return -ENODEV;
@@ -2588,8 +2552,7 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
int ret;
- uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+ uea_dbg(usb, "ADSL device found with vid (%#X) pid (%#X) Rev (%#X): %s\n",
le16_to_cpu(usb->descriptor.idVendor),
le16_to_cpu(usb->descriptor.idProduct),
le16_to_cpu(usb->descriptor.bcdDevice),
@@ -2597,8 +2560,23 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_reset_device(usb);
- if (UEA_IS_PREFIRM(id))
- return uea_load_firmware(usb, UEA_CHIP_VERSION(id));
+ if (UEA_IS_PREFIRM(id)) {
+ struct completion *fw_done;
+
+ /* Wait for the firmware load to be done, in .disconnect() */
+ fw_done = kzalloc_obj(*fw_done);
+ if (!fw_done)
+ return -ENOMEM;
+
+ init_completion(fw_done);
+ usb_set_intfdata(intf, fw_done);
+
+ ret = uea_load_firmware(intf, UEA_CHIP_VERSION(id));
+ if (ret)
+ kfree(fw_done);
+
+ return ret;
+ }
ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver);
if (ret == 0) {
@@ -2619,7 +2597,6 @@ static void uea_disconnect(struct usb_interface *intf)
{
struct usb_device *usb = interface_to_usbdev(intf);
int ifnum = intf->altsetting->desc.bInterfaceNumber;
- uea_enters(usb);
/* ADI930 has 2 interfaces and eagle 3 interfaces.
* Pre-firmware device has one interface
@@ -2629,9 +2606,14 @@ static void uea_disconnect(struct usb_interface *intf)
usbatm_usb_disconnect(intf);
mutex_unlock(&uea_mutex);
uea_info(usb, "ADSL device removed\n");
- }
+ } else if (usb->config->desc.bNumInterfaces == 1) {
+ struct completion *fw_done = usb_get_intfdata(intf);
- uea_leaves(usb);
+ uea_dbg(usb, "pre-firmware device, waiting firmware upload\n");
+ wait_for_completion(fw_done);
+ uea_dbg(usb, "pre-firmware device, finished waiting\n");
+ kfree(fw_done);
+ }
}
/*
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a1f99c3b5f37..f0a9bb5754a3 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -781,6 +781,24 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
return 0;
}
+static void dwc3_ulpi_setup(struct dwc3 *dwc)
+{
+ int index;
+ u32 reg;
+
+ /* Don't do anything if there is no ULPI PHY */
+ if (!dwc->ulpi)
+ return;
+
+ if (dwc->enable_usb2_transceiver_delay) {
+ for (index = 0; index < dwc->num_usb2_ports; index++) {
+ reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
+ reg |= DWC3_GUSB2PHYCFG_XCVRDLY;
+ dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
+ }
+ }
+}
+
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -1355,6 +1373,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc->ulpi_ready = true;
}
+ dwc3_ulpi_setup(dwc);
+
if (!dwc->phys_ready) {
ret = dwc3_core_get_phy(dwc);
if (ret)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index a35b3db1f9f3..a39bf284c763 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -302,6 +302,7 @@
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
+#define DWC3_GUSB2PHYCFG_XCVRDLY BIT(9)
#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
@@ -1161,6 +1162,8 @@ struct dwc3_glue_ops {
* 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk.
* @dis_split_quirk: set to disable split boundary.
+ * @enable_usb2_transceiver_delay: Set to insert a delay before the
+ * assertion of the TxValid signal during a HS Chirp.
* @sys_wakeup: set if the device may do system wakeup.
* @wakeup_configured: set if the device is configured for remote wakeup.
* @suspended: set to track suspend event due to U3/L2.
@@ -1403,6 +1406,7 @@ struct dwc3 {
unsigned dis_metastability_quirk:1;
unsigned dis_split_quirk:1;
+ unsigned enable_usb2_transceiver_delay:1;
unsigned async_callbacks:1;
unsigned sys_wakeup:1;
unsigned wakeup_configured:1;
diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c
index 57daad15f502..a256b7f5d78b 100644
--- a/drivers/usb/dwc3/ulpi.c
+++ b/drivers/usb/dwc3/ulpi.c
@@ -10,10 +10,13 @@
#include <linux/delay.h>
#include <linux/time64.h>
#include <linux/ulpi/regs.h>
+#include <linux/ulpi/driver.h>
#include "core.h"
#include "io.h"
+#define USB_VENDOR_MICROCHIP 0x0424
+
#define DWC3_ULPI_ADDR(a) \
((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
@@ -83,6 +86,26 @@ static const struct ulpi_ops dwc3_ulpi_ops = {
.write = dwc3_ulpi_write,
};
+static void dwc3_ulpi_detect_config(struct dwc3 *dwc)
+{
+ struct ulpi *ulpi = dwc->ulpi;
+
+ switch (ulpi->id.vendor) {
+ case USB_VENDOR_MICROCHIP:
+ switch (ulpi->id.product) {
+ case 0x0009:
+ /* Microchip USB3340 ULPI PHY */
+ dwc->enable_usb2_transceiver_delay = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
int dwc3_ulpi_init(struct dwc3 *dwc)
{
/* Register the interface */
@@ -92,6 +115,8 @@ int dwc3_ulpi_init(struct dwc3 *dwc)
return PTR_ERR(dwc->ulpi);
}
+ dwc3_ulpi_detect_config(dwc);
+
return 0;
}
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 5ef9a7a7f3bc..311606097718 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -162,8 +162,6 @@ struct ffs_epfile {
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
- struct dentry *dentry;
-
/*
* Buffer for holding data from partial reads which may happen since
* we’re rounding user read requests to a multiple of a max packet size.
@@ -273,11 +271,11 @@ struct ffs_desc_helper {
};
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+static void ffs_epfiles_destroy(struct super_block *sb,
+ struct ffs_epfile *epfiles, unsigned count);
-static struct dentry *
-ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
- const struct file_operations *fops);
+static int ffs_sb_create_file(struct super_block *sb, const char *name,
+ void *data, const struct file_operations *fops);
/* Devices management *******************************************************/
@@ -291,6 +289,7 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data);
static void ffs_release_dev(struct ffs_dev *ffs_dev);
static int ffs_ready(struct ffs_data *ffs);
static void ffs_closed(struct ffs_data *ffs);
+static void ffs_reset_work(struct work_struct *work);
/* Misc helper functions ****************************************************/
@@ -1354,7 +1353,6 @@ ffs_epfile_release(struct inode *inode, struct file *file)
mutex_unlock(&epfile->dmabufs_mutex);
- __ffs_epfile_read_buffer_free(epfile);
ffs_data_closed(epfile->ffs);
return 0;
@@ -1881,9 +1879,8 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
}
/* Create "regular" file */
-static struct dentry *ffs_sb_create_file(struct super_block *sb,
- const char *name, void *data,
- const struct file_operations *fops)
+static int ffs_sb_create_file(struct super_block *sb, const char *name,
+ void *data, const struct file_operations *fops)
{
struct ffs_data *ffs = sb->s_fs_info;
struct dentry *dentry;
@@ -1891,16 +1888,16 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
dentry = d_alloc_name(sb->s_root, name);
if (!dentry)
- return NULL;
+ return -ENOMEM;
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
if (!inode) {
dput(dentry);
- return NULL;
+ return -ENOMEM;
}
d_add(dentry, inode);
- return dentry;
+ return 0;
}
/* Super block */
@@ -1943,10 +1940,7 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
return -ENOMEM;
/* EP0 file */
- if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
- return -ENOMEM;
-
- return 0;
+ return ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations);
}
enum {
@@ -2086,12 +2080,18 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
return 0;
}
+static void ffs_data_reset(struct ffs_data *ffs);
+
static void
ffs_fs_kill_sb(struct super_block *sb)
{
kill_litter_super(sb);
- if (sb->s_fs_info)
- ffs_data_closed(sb->s_fs_info);
+ if (sb->s_fs_info) {
+ struct ffs_data *ffs = sb->s_fs_info;
+ ffs->state = FFS_CLOSING;
+ ffs_data_reset(ffs);
+ ffs_data_put(ffs);
+ }
}
static struct file_system_type ffs_fs_type = {
@@ -2129,7 +2129,6 @@ static void functionfs_cleanup(void)
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
-static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{
@@ -2138,7 +2137,6 @@ static void ffs_data_get(struct ffs_data *ffs)
static void ffs_data_opened(struct ffs_data *ffs)
{
- refcount_inc(&ffs->ref);
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
@@ -2163,11 +2161,11 @@ static void ffs_data_put(struct ffs_data *ffs)
static void ffs_data_closed(struct ffs_data *ffs)
{
- struct ffs_epfile *epfiles;
- unsigned long flags;
-
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
+ struct ffs_epfile *epfiles;
+ unsigned long flags;
+
ffs->state = FFS_DEACTIVATED;
spin_lock_irqsave(&ffs->eps_lock, flags);
epfiles = ffs->epfiles;
@@ -2176,7 +2174,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
flags);
if (epfiles)
- ffs_epfiles_destroy(epfiles,
+ ffs_epfiles_destroy(ffs->sb, epfiles,
ffs->eps_count);
if (ffs->setup_state == FFS_SETUP_PENDING)
@@ -2186,12 +2184,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
ffs_data_reset(ffs);
}
}
- if (atomic_read(&ffs->opened) < 0) {
- ffs->state = FFS_CLOSING;
- ffs_data_reset(ffs);
- }
-
- ffs_data_put(ffs);
}
static struct ffs_data *ffs_data_new(const char *dev_name)
@@ -2214,6 +2206,7 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
init_waitqueue_head(&ffs->ev.waitq);
init_waitqueue_head(&ffs->wait);
init_completion(&ffs->ep0req_completion);
+ INIT_WORK(&ffs->reset_work, ffs_reset_work);
/* XXX REVISIT need to update it in some places, or do we? */
ffs->ev.can_stall = 1;
@@ -2241,7 +2234,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
* copy of epfile will save us from use-after-free.
*/
if (epfiles) {
- ffs_epfiles_destroy(epfiles, ffs->eps_count);
+ ffs_epfiles_destroy(ffs->sb, epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
@@ -2338,6 +2331,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
unsigned i, count;
+ int err;
count = ffs->eps_count;
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
@@ -2355,12 +2349,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
else
sprintf(epfile->name, "ep%u", i);
epfile->in = (ffs->eps_addrmap[i] & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
- epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
- epfile,
- &ffs_epfile_operations);
- if (!epfile->dentry) {
- ffs_epfiles_destroy(epfiles, i - 1);
- return -ENOMEM;
+ err = ffs_sb_create_file(ffs->sb, epfile->name,
+ epfile, &ffs_epfile_operations);
+ if (err) {
+ ffs_epfiles_destroy(ffs->sb, epfiles, i - 1);
+ return err;
}
}
@@ -2368,16 +2361,16 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
return 0;
}
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+static void ffs_epfiles_destroy(struct super_block *sb,
+ struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
+ struct dentry *root = sb->s_root;
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
- if (epfile->dentry) {
- simple_recursive_removal(epfile->dentry, NULL);
- epfile->dentry = NULL;
- }
+ __ffs_epfile_read_buffer_free(epfile);
+ simple_remove_by_name(root, epfile->name, NULL);
}
kfree(epfiles);
@@ -3745,6 +3738,7 @@ static int ffs_func_set_alt(struct usb_function *f,
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
+ unsigned long flags;
int ret = 0, intf;
if (alt > MAX_ALT_SETTINGS)
@@ -3757,12 +3751,14 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func)
ffs_func_eps_disable(ffs->func);
+ spin_lock_irqsave(&ffs->eps_lock, flags);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
- INIT_WORK(&ffs->reset_work, ffs_reset_work);
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
@@ -3780,16 +3776,19 @@ static void ffs_func_disable(struct usb_function *f)
{
struct ffs_function *func = ffs_func_from_usb(f);
struct ffs_data *ffs = func->ffs;
+ unsigned long flags;
if (ffs->func)
ffs_func_eps_disable(ffs->func);
+ spin_lock_irqsave(&ffs->eps_lock, flags);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
- INIT_WORK(&ffs->reset_work, ffs_reset_work);
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
schedule_work(&ffs->reset_work);
return;
}
+ spin_unlock_irqrestore(&ffs->eps_lock, flags);
if (ffs->state == FFS_ACTIVE) {
ffs->func = NULL;
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 4b5f03f683f7..8fbbf9e195b0 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1685,6 +1685,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
case ClearHubFeature:
break;
case ClearPortFeature:
+ if (index != 1)
+ goto error;
switch (value) {
case USB_PORT_FEAT_SUSPEND:
break;
@@ -1694,6 +1696,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
!pdata->vbus_active_level);
fallthrough;
default:
+ if (value >= 32)
+ goto error;
max3421_hcd->port_status &= ~(1 << value);
}
break;
@@ -1726,6 +1730,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
break;
case SetPortFeature:
+ if (index != 1)
+ goto error;
switch (value) {
case USB_PORT_FEAT_LINK_STATE:
case USB_PORT_FEAT_U1_TIMEOUT:
@@ -1747,6 +1753,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
max3421_reset_port(hcd);
fallthrough;
default:
+ if (value >= 32)
+ goto error;
if ((max3421_hcd->port_status & USB_PORT_STAT_POWER)
!= 0)
max3421_hcd->port_status |= (1 << value);