mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
MMC core:
- Fix RPMB device unregister ordering
- Fix __counted_by handling in mmc_test
MMC host:
- mtk-sd: Document missing clocks for MT8189
- sdhci-esdhc-imx: Fix the support for system suspend/resume for SDIO
- sdhci-of-dwcmshc: Fix error handling for clock prepare/enable
- vub300: Fix lockdep issue for the cmd_mutex
- vub300: Fix use-after-free on probe failure
MEMSTICK:
- Reject a card that reports too many blocks
-----BEGIN PGP SIGNATURE-----
iQJEBAABCgAuFiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmpaF4YQHHVsZmhAa2Vy
bmVsLm9yZwAKCRD+JoQlc1iMKQsXEAC4Y3DuRvuYUi3MVeAI8IqXZKW1qZ2Wg7pD
tvjbS0h1ZLVBPXeWIhjL2N9Y2GWIzbq5Yb0zAyqwl4d99IsNL5j0ul6rQbVWHY6Z
48IJ8idboGeUXZ9foUif8t+gZOVUd6Mecf8GxWkJcwlJ70pt36TCGWPvp3/MkQmP
w6srlDXfIZgQyauQIz+cHYcocD0L7vp6apAcT/QQRLadY4PBpzNfjjgbqr5ogejF
ovRkTUBp2D/ufTV0p8V0ykQ9onac7aV1HrX1ubSjs/2rkxNMOBGRYTeds8YYm4Of
Jljdivx0EeLA638sJ7XO6QGbxT7pwwffRzS+q6VE+NilKghwF3/GE1LPv8NSV+mA
woeSxPCgVxfqF+THGQE9J8NQXtIV6UF7gNHVSp+Vq/aKuykSwnRslUbu7mncgDZC
nv2cwcmlVU98IKDNVFNNMCkMbaEyifWzaxR6gX2Xlo+Qo6n3A/Qz6bSjw5LTkIyg
sAx0jmSKWbgpRZl4eYO16DKDwOkGW5zDEhjxQqtRBcyxv7Yndgl+lcP/fPR0oVCT
/gyZOEsFg3ItfUCW5nMnTRWZ6u8D7tSXXVXaqs8b4HB8Nj7jX2WHfkrmT0+i8oMu
eGXITNNOWp827RZHX1uxzoBMQXfHVIZq8FVECAcrCxnzQz4E5zpP3JKTzz9ydpe6
VG49Xs+JsA==
=IHdC
-----END PGP SIGNATURE-----
Merge tag 'mmc-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC fixes from Ulf Hansson:
"MMC core:
- Fix RPMB device unregister ordering
- Fix __counted_by handling in mmc_test
MMC host:
- mtk-sd: Document missing clocks for MT8189
- sdhci-esdhc-imx: Fix the support for system suspend/resume for SDIO
- sdhci-of-dwcmshc: Fix error handling for clock prepare/enable
- vub300:
- Fix lockdep issue for the cmd_mutex
- Fix use-after-free on probe failure
MEMSTICK:
- Reject a card that reports too many blocks"
* tag 'mmc-v7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
mmc: sdhci-esdhc-imx: fix resume error handling
mmc: sdhci-esdhc-imx: make non-fatal errors non-blocking in suspend
mmc: sdhci-esdhc-imx: use pm_runtime_resume_and_get() in suspend
mmc: sdhci-esdhc-imx: disable irq during suspend to fix unhandled interrupt
mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
mmc: sdhci-esdhc-imx: fix esdhc_change_pinstate() to allow default state restore
mmc: sdhci-esdhc-imx: restore DLL override for DDR modes on resume
mmc: sdhci-esdhc-imx: remove unnecessary mmc_card_wake_sdio_irq check for tuning save/restore
mmc: block: fix RPMB device unregister ordering
memstick: ms_block: reject a card that reports too many blocks
dt-bindings: mmc: mtk-sd: Document extra clocks for MT8189
mmc: vub300: defer reset until cmd_mutex is unlocked
mmc: vub300: fix use-after-free on probe failure
mmc: mmc_test: Fix __counted_by handling after kzalloc_flex() conversion
mmc: sdhci-of-dwcmshc: check bus clock enable result in the probe() method
This commit is contained in:
commit
45419d06c9
|
|
@ -193,7 +193,6 @@ allOf:
|
|||
- mediatek,mt8183-mmc
|
||||
- mediatek,mt8186-mmc
|
||||
- mediatek,mt8188-mmc
|
||||
- mediatek,mt8189-mmc
|
||||
- mediatek,mt8195-mmc
|
||||
- mediatek,mt8196-mmc
|
||||
- mediatek,mt8516-mmc
|
||||
|
|
@ -348,6 +347,34 @@ allOf:
|
|||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8189-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
- description: bus clock used for internal register access
|
||||
- description: peripheral bus clock gate
|
||||
- description: AXI bus clock gate
|
||||
- description: crypto clock used for data encrypt/decrypt (optional)
|
||||
clock-names:
|
||||
minItems: 6
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: bus_clk
|
||||
- const: pclk_cg
|
||||
- const: axi_cg
|
||||
- const: crypto
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -1338,6 +1338,10 @@ static int msb_ftl_initialize(struct msb_data *msb)
|
|||
return 0;
|
||||
|
||||
msb->zone_count = msb->block_count / MS_BLOCKS_IN_ZONE;
|
||||
if (msb->block_count > MS_MAX_ZONES * MS_BLOCKS_IN_ZONE) {
|
||||
pr_err("Too many blocks: %d\n", msb->block_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
msb->logical_block_count = msb->zone_count * 496 - 2;
|
||||
|
||||
msb->used_blocks_bitmap = bitmap_zalloc(msb->block_count, GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -2715,7 +2715,6 @@ static void mmc_blk_rpmb_device_release(struct device *dev)
|
|||
{
|
||||
struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
|
||||
|
||||
rpmb_dev_unregister(rpmb->rdev);
|
||||
mmc_blk_put(rpmb->md);
|
||||
ida_free(&mmc_rpmb_ida, rpmb->id);
|
||||
kfree(rpmb);
|
||||
|
|
@ -2930,8 +2929,8 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
|
|||
}
|
||||
|
||||
static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
|
||||
|
||||
{
|
||||
rpmb_dev_unregister(rpmb->rdev);
|
||||
cdev_device_del(&rpmb->chrdev, &rpmb->dev);
|
||||
put_device(&rpmb->dev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,9 +318,9 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
|
|||
{
|
||||
if (!mem)
|
||||
return;
|
||||
while (mem->cnt--)
|
||||
__free_pages(mem->arr[mem->cnt].page,
|
||||
mem->arr[mem->cnt].order);
|
||||
for (unsigned int i = 0; i < mem->cnt; i++)
|
||||
__free_pages(mem->arr[i].page,
|
||||
mem->arr[i].order);
|
||||
kfree(mem);
|
||||
}
|
||||
|
||||
|
|
@ -341,6 +341,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
|
|||
unsigned long page_cnt = 0;
|
||||
unsigned long limit = nr_free_buffer_pages() >> 4;
|
||||
struct mmc_test_mem *mem;
|
||||
unsigned int idx = 0;
|
||||
|
||||
if (max_page_cnt > limit)
|
||||
max_page_cnt = limit;
|
||||
|
|
@ -375,23 +376,26 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
|
|||
goto out_free;
|
||||
break;
|
||||
}
|
||||
mem->arr[mem->cnt].page = page;
|
||||
mem->arr[mem->cnt].order = order;
|
||||
mem->cnt += 1;
|
||||
mem->arr[idx].page = page;
|
||||
mem->arr[idx].order = order;
|
||||
idx += 1;
|
||||
if (max_page_cnt <= (1UL << order))
|
||||
break;
|
||||
max_page_cnt -= 1UL << order;
|
||||
page_cnt += 1UL << order;
|
||||
if (mem->cnt >= max_segs) {
|
||||
if (idx >= mem->cnt) {
|
||||
if (page_cnt < min_page_cnt)
|
||||
goto out_free;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mem->cnt = idx;
|
||||
|
||||
return mem;
|
||||
|
||||
out_free:
|
||||
mem->cnt = idx;
|
||||
mmc_test_free_mem(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1326,19 +1326,21 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
|
|||
|
||||
dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
|
||||
|
||||
if (IS_ERR(imx_data->pinctrl) ||
|
||||
IS_ERR(imx_data->pins_100mhz) ||
|
||||
IS_ERR(imx_data->pins_200mhz))
|
||||
if (IS_ERR(imx_data->pinctrl))
|
||||
return -EINVAL;
|
||||
|
||||
switch (uhs) {
|
||||
case MMC_TIMING_UHS_SDR50:
|
||||
case MMC_TIMING_UHS_DDR50:
|
||||
if (IS_ERR(imx_data->pins_100mhz))
|
||||
return -EINVAL;
|
||||
pinctrl = imx_data->pins_100mhz;
|
||||
break;
|
||||
case MMC_TIMING_UHS_SDR104:
|
||||
case MMC_TIMING_MMC_HS200:
|
||||
case MMC_TIMING_MMC_HS400:
|
||||
if (IS_ERR(imx_data->pins_200mhz))
|
||||
return -EINVAL;
|
||||
pinctrl = imx_data->pins_200mhz;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1349,6 +1351,23 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
|
|||
return pinctrl_select_state(imx_data->pinctrl, pinctrl);
|
||||
}
|
||||
|
||||
static void esdhc_set_dll_override(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
|
||||
u32 v;
|
||||
|
||||
if (!boarddata->delay_line)
|
||||
return;
|
||||
|
||||
v = boarddata->delay_line << ESDHC_DLL_OVERRIDE_VAL_SHIFT |
|
||||
(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
|
||||
if (is_imx53_esdhc(imx_data))
|
||||
v <<= 1;
|
||||
writel(v, host->ioaddr + ESDHC_DLL_CTRL);
|
||||
}
|
||||
|
||||
/*
|
||||
* For HS400 eMMC, there is a data_strobe line. This signal is generated
|
||||
* by the device and used for data output and CRC status response output
|
||||
|
|
@ -1404,7 +1423,6 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
|
|||
u32 m;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
|
||||
|
||||
/* disable ddr mode and disable HS400 mode */
|
||||
m = readl(host->ioaddr + ESDHC_MIX_CTRL);
|
||||
|
|
@ -1425,15 +1443,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
|
|||
m |= ESDHC_MIX_CTRL_DDREN;
|
||||
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
|
||||
imx_data->is_ddr = 1;
|
||||
if (boarddata->delay_line) {
|
||||
u32 v;
|
||||
v = boarddata->delay_line <<
|
||||
ESDHC_DLL_OVERRIDE_VAL_SHIFT |
|
||||
(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
|
||||
if (is_imx53_esdhc(imx_data))
|
||||
v <<= 1;
|
||||
writel(v, host->ioaddr + ESDHC_DLL_CTRL);
|
||||
}
|
||||
esdhc_set_dll_override(host);
|
||||
break;
|
||||
case MMC_TIMING_MMC_HS400:
|
||||
m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
|
||||
|
|
@ -2051,7 +2061,9 @@ static int sdhci_esdhc_suspend(struct device *dev)
|
|||
* 2, make sure the pm_runtime_force_resume() in sdhci_esdhc_resume() really
|
||||
* invoke its ->runtime_resume callback (needs_force_resume = 1).
|
||||
*/
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
|
||||
(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
|
||||
|
|
@ -2064,15 +2076,14 @@ static int sdhci_esdhc_suspend(struct device *dev)
|
|||
* to save the tuning delay value just in case the usdhc
|
||||
* lost power during system PM.
|
||||
*/
|
||||
if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
|
||||
esdhc_is_usdhc(imx_data))
|
||||
if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data))
|
||||
sdhc_esdhc_tuning_save(host);
|
||||
|
||||
/* The irqs of imx are not shared. It is safe to disable */
|
||||
disable_irq(host->irq);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
/* The irqs of imx are not shared. It is safe to disable */
|
||||
disable_irq(host->irq);
|
||||
ret = sdhci_enable_irq_wakeups(host);
|
||||
if (!ret)
|
||||
if (!sdhci_enable_irq_wakeups(host))
|
||||
dev_warn(dev, "Failed to enable irq wakeup\n");
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -2083,12 +2094,12 @@ static int sdhci_esdhc_suspend(struct device *dev)
|
|||
* other function like GPIO function to save power in PM,
|
||||
* which finally block the SDIO wakeup function.
|
||||
*/
|
||||
ret = pinctrl_pm_select_sleep_state(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (pinctrl_pm_select_sleep_state(dev))
|
||||
dev_warn(dev, "Failed to select sleep pinctrl state\n");
|
||||
}
|
||||
|
||||
ret = mmc_gpio_set_cd_wake(host->mmc, true);
|
||||
if (mmc_gpio_set_cd_wake(host->mmc, true))
|
||||
dev_warn(dev, "Failed to enable cd wake\n");
|
||||
|
||||
/*
|
||||
* Make sure invoke runtime_suspend to gate off clock.
|
||||
|
|
@ -2096,7 +2107,7 @@ static int sdhci_esdhc_suspend(struct device *dev)
|
|||
*/
|
||||
pm_runtime_force_suspend(dev);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_esdhc_resume(struct device *dev)
|
||||
|
|
@ -2106,31 +2117,45 @@ static int sdhci_esdhc_resume(struct device *dev)
|
|||
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
int ret;
|
||||
|
||||
pm_runtime_force_resume(dev);
|
||||
if (!device_may_wakeup(dev)) {
|
||||
ret = esdhc_change_pinstate(host, host->timing);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to restore pinctrl state\n");
|
||||
}
|
||||
|
||||
ret = mmc_gpio_set_cd_wake(host->mmc, false);
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mmc_gpio_set_cd_wake(host->mmc, false);
|
||||
|
||||
/* re-initialize hw state in case it's lost in low power mode */
|
||||
sdhci_esdhc_imx_hwinit(host);
|
||||
|
||||
if (host->irq_wake_enabled) {
|
||||
if (host->irq_wake_enabled)
|
||||
sdhci_disable_irq_wakeups(host);
|
||||
enable_irq(host->irq);
|
||||
}
|
||||
|
||||
enable_irq(host->irq);
|
||||
|
||||
/*
|
||||
* restore the saved tuning delay value for the device which keep
|
||||
* power during system PM.
|
||||
*/
|
||||
if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) &&
|
||||
esdhc_is_usdhc(imx_data))
|
||||
if (mmc_card_keep_power(host->mmc) && esdhc_is_usdhc(imx_data)) {
|
||||
sdhc_esdhc_tuning_restore(host);
|
||||
|
||||
/*
|
||||
* Restore DLL override for DDR modes. hwinit unconditionally
|
||||
* clears ESDHC_DLL_CTRL, but the card is still in DDR mode.
|
||||
*/
|
||||
if (host->timing == MMC_TIMING_UHS_DDR50 ||
|
||||
host->timing == MMC_TIMING_MMC_DDR52)
|
||||
esdhc_set_dll_override(host);
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_esdhc_runtime_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -2433,13 +2433,16 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
|
||||
priv->bus_clk = devm_clk_get(dev, "bus");
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
if (!IS_ERR(priv->bus_clk)) {
|
||||
err = clk_prepare_enable(priv->bus_clk);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
|
||||
err = mmc_of_parse(host->mmc);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
goto err_bus_clk;
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
|
|
@ -2453,7 +2456,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
|||
if (pltfm_data->init) {
|
||||
err = pltfm_data->init(&pdev->dev, host, priv);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
goto err_bus_clk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
|
@ -2499,9 +2502,10 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
|||
err_rpm:
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
err_bus_clk:
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
err_clk:
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1586,7 +1586,7 @@ static int __command_write_data(struct vub300_mmc_host *vub300,
|
|||
return linear_length;
|
||||
}
|
||||
|
||||
static void __vub300_command_response(struct vub300_mmc_host *vub300,
|
||||
static bool __vub300_command_response(struct vub300_mmc_host *vub300,
|
||||
struct mmc_command *cmd,
|
||||
struct mmc_data *data, int data_length)
|
||||
{
|
||||
|
|
@ -1598,17 +1598,11 @@ static void __vub300_command_response(struct vub300_mmc_host *vub300,
|
|||
msecs_to_jiffies(msec_timeout));
|
||||
if (respretval == 0) { /* TIMED OUT */
|
||||
/* we don't know which of "out" and "res" if any failed */
|
||||
int result;
|
||||
vub300->usb_timed_out = 1;
|
||||
usb_kill_urb(vub300->command_out_urb);
|
||||
usb_kill_urb(vub300->command_res_urb);
|
||||
cmd->error = -ETIMEDOUT;
|
||||
result = usb_lock_device_for_reset(vub300->udev,
|
||||
vub300->interface);
|
||||
if (result == 0) {
|
||||
result = usb_reset_device(vub300->udev);
|
||||
usb_unlock_device(vub300->udev);
|
||||
}
|
||||
return true;
|
||||
} else if (respretval < 0) {
|
||||
/* we don't know which of "out" and "res" if any failed */
|
||||
usb_kill_urb(vub300->command_out_urb);
|
||||
|
|
@ -1704,6 +1698,8 @@ static void __vub300_command_response(struct vub300_mmc_host *vub300,
|
|||
} else {
|
||||
cmd->error = -EINVAL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void construct_request_response(struct vub300_mmc_host *vub300,
|
||||
|
|
@ -1749,6 +1745,7 @@ static void vub300_cmndwork_thread(struct work_struct *work)
|
|||
struct mmc_request *req = vub300->req;
|
||||
struct mmc_command *cmd = vub300->cmd;
|
||||
struct mmc_data *data = vub300->data;
|
||||
bool reset_device;
|
||||
int data_length;
|
||||
mutex_lock(&vub300->cmd_mutex);
|
||||
init_completion(&vub300->command_complete);
|
||||
|
|
@ -1771,7 +1768,8 @@ static void vub300_cmndwork_thread(struct work_struct *work)
|
|||
data_length = __command_read_data(vub300, cmd, data);
|
||||
else
|
||||
data_length = __command_write_data(vub300, cmd, data);
|
||||
__vub300_command_response(vub300, cmd, data, data_length);
|
||||
reset_device = __vub300_command_response(vub300, cmd,
|
||||
data, data_length);
|
||||
vub300->req = NULL;
|
||||
vub300->cmd = NULL;
|
||||
vub300->data = NULL;
|
||||
|
|
@ -1779,6 +1777,16 @@ static void vub300_cmndwork_thread(struct work_struct *work)
|
|||
if (cmd->error == -ENOMEDIUM)
|
||||
check_vub300_port_status(vub300);
|
||||
mutex_unlock(&vub300->cmd_mutex);
|
||||
if (reset_device) {
|
||||
int result;
|
||||
|
||||
result = usb_lock_device_for_reset(vub300->udev,
|
||||
vub300->interface);
|
||||
if (result == 0) {
|
||||
result = usb_reset_device(vub300->udev);
|
||||
usb_unlock_device(vub300->udev);
|
||||
}
|
||||
}
|
||||
mmc_request_done(vub300->mmc, req);
|
||||
kref_put(&vub300->kref, vub300_delete);
|
||||
return;
|
||||
|
|
@ -2336,12 +2344,16 @@ static int vub300_probe(struct usb_interface *interface,
|
|||
interface_to_InterfaceNumber(interface));
|
||||
retval = mmc_add_host(mmc);
|
||||
if (retval)
|
||||
goto err_delete_timer;
|
||||
goto err_stop_io;
|
||||
|
||||
return 0;
|
||||
|
||||
err_delete_timer:
|
||||
timer_delete_sync(&vub300->inactivity_timer);
|
||||
err_stop_io:
|
||||
vub300->interface = NULL;
|
||||
kref_put(&vub300->kref, vub300_delete);
|
||||
|
||||
return retval;
|
||||
|
||||
err_free_host:
|
||||
mmc_free_host(mmc);
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user