diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index e61c0667b53a..6a67e2ed75d9 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2837,16 +2837,154 @@ int fsg_common_set_cdev(struct fsg_common *common, return 0; } +static inline int fsg_common_add_sysfs(struct fsg_common *common, + struct fsg_lun *lun) +{ + int rc; + + rc = device_register(&lun->dev); + if (rc) { + put_device(&lun->dev); + return rc; + } + + rc = device_create_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + if (rc) + goto error; + rc = device_create_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + if (rc) + goto error; + rc = device_create_file(&lun->dev, &dev_attr_nofua); + if (rc) + goto error; + + return 0; + +error: + /* removing nonexistent files is a no-op */ + fsg_common_remove_sysfs(lun); + device_unregister(&lun->dev); + return rc; +} + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id, const char *name, + const char **name_pfx) +{ + struct fsg_lun *lun; + char *pathbuf, *p; + int rc = -ENOMEM; + + if (!common->nluns || !common->luns) + return -ENODEV; + + if (common->luns[id]) + return -EBUSY; + + if (!cfg->filename && !cfg->removable) { + pr_err("no file given for LUN%d\n", id); + return -EINVAL; + } + + lun = kzalloc(sizeof(*lun), GFP_KERNEL); + if (!lun) + return -ENOMEM; + + lun->name_pfx = name_pfx; + + lun->cdrom = !!cfg->cdrom; + lun->ro = cfg->cdrom || cfg->ro; + lun->initially_ro = lun->ro; + lun->removable = !!cfg->removable; + + if (!common->sysfs) { + /* we DON'T own the name!*/ + lun->name = name; + } else { + lun->dev.release = fsg_lun_release; + lun->dev.parent = &common->gadget->dev; + dev_set_drvdata(&lun->dev, &common->filesem); + dev_set_name(&lun->dev, name); + lun->name = dev_name(&lun->dev); + + rc = fsg_common_add_sysfs(common, lun); + if (rc) { + pr_info("failed to register LUN%d: %d\n", id, rc); + goto error_sysfs; + } + } + + common->luns[id] = lun; + + if (cfg->filename) { + rc = fsg_lun_open(lun, cfg->filename); + if (rc) + goto error_lun; + } + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + p = "(no medium)"; + if (fsg_lun_is_open(lun)) { + p = "(error)"; + if (pathbuf) { + p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = "(error)"; + } + } + pr_info("LUN: %s%s%sfile: %s\n", + lun->removable ? "removable " : "", + lun->ro ? "read only " : "", + lun->cdrom ? "CD-ROM " : "", + p); + kfree(pathbuf); + + return 0; + +error_lun: + if (common->sysfs) { + fsg_common_remove_sysfs(lun); + device_unregister(&lun->dev); + } + fsg_lun_close(lun); + common->luns[id] = NULL; +error_sysfs: + kfree(lun); + return rc; +} + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) +{ + char buf[8]; /* enough for 100000000 different numbers, decimal */ + int i, rc; + + for (i = 0; i < common->nluns; ++i) { + snprintf(buf, sizeof(buf), "lun%d", i); + rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); + if (rc) + goto fail; + } + + pr_info("Number of LUNs=%d\n", common->nluns); + + return 0; + +fail: + _fsg_common_remove_luns(common, i); + return rc; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) { - struct usb_gadget *gadget = cdev->gadget; - struct fsg_lun **curlun_it; - struct fsg_lun_config *lcfg; - int nluns, i, rc; - char *pathbuf; - + int i, rc; common = fsg_common_setup(common); if (IS_ERR(common)) @@ -2870,66 +3008,10 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, rc = fsg_common_set_nluns(common, cfg->nluns); if (rc) goto error_release; - curlun_it = common->luns; - nluns = cfg->nluns; - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { - struct fsg_lun *curlun; - - curlun = kzalloc(sizeof(*curlun), GFP_KERNEL); - if (!curlun) { - rc = -ENOMEM; - common->nluns = i; - goto error_release; - } - *curlun_it = curlun; - - curlun->cdrom = !!lcfg->cdrom; - curlun->ro = lcfg->cdrom || lcfg->ro; - curlun->initially_ro = curlun->ro; - curlun->removable = lcfg->removable; - curlun->dev.release = fsg_lun_release; - curlun->dev.parent = &gadget->dev; - /* curlun->dev.driver = &fsg_driver.driver; XXX */ - dev_set_drvdata(&curlun->dev, &common->filesem); - dev_set_name(&curlun->dev, "lun%d", i); - curlun->name = dev_name(&curlun->dev); - - rc = device_register(&curlun->dev); - if (rc) { - INFO(common, "failed to register LUN%d: %d\n", i, rc); - common->nluns = i; - put_device(&curlun->dev); - kfree(curlun); - goto error_release; - } - - rc = device_create_file(&curlun->dev, - curlun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, - curlun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto error_luns; - - if (lcfg->filename) { - rc = fsg_lun_open(curlun, lcfg->filename); - if (rc) - goto error_luns; - } else if (!curlun->removable) { - ERROR(common, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto error_luns; - } - } + rc = fsg_common_create_luns(common, cfg); + if (rc) + goto error_release; /* Prepare inquiryString */ i = get_default_bcdDevice(); @@ -2941,7 +3023,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, : "File-Stor Gadget"), i); - /* Tell the thread to start working */ common->thread_task = kthread_create(fsg_main_thread, common, "file-storage"); @@ -2954,37 +3035,12 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); INFO(common, "Number of LUNs=%d\n", common->nluns); - pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0, nluns = common->nluns, curlun_it = common->luns; - i < nluns; - ++curlun_it, ++i) { - struct fsg_lun *curlun = *curlun_it; - char *p = "(no medium)"; - if (fsg_lun_is_open(curlun)) { - p = "(error)"; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = "(error)"; - } - } - LINFO(curlun, "LUN: %s%s%sfile: %s\n", - curlun->removable ? "removable " : "", - curlun->ro ? "read only " : "", - curlun->cdrom ? "CD-ROM " : "", - p); - } - kfree(pathbuf); - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); wake_up_process(common->thread_task); return common; -error_luns: - common->nluns = i + 1; error_release: common->state = FSG_STATE_TERMINATED; /* The thread is dead */ /* Call fsg_common_release() directly, ref might be not initialised. */ diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index de7aa32565b4..2a51e7b1cc60 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -117,6 +117,12 @@ void fsg_common_free_luns(struct fsg_common *common); int fsg_common_set_nluns(struct fsg_common *common, int nluns); +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id, const char *name, + const char **name_pfx); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers);