When configfs is in place, the things related to intialization
of struct fsg_common will be split over a number of places.
This patch adds several functions which together cover the former
intialization routine fsg_common_init.

When configfs is in place, the luns will not be represented in sysfs,
so there will be no struct device associated with a lun.
To prepare for this some debug macros need to be adjusted. Two new
fields are added to struct fsg_lun: name and name_pfx.
The "name" is for storing a string which is presented to the user
instead of the dev_name. The "name_pfx", if non-NULL, is prepended
to the "name" at printing time.

The name_pfx is for a future lun.0, which will be a default group in
mass_storage.<name>. By design at USB function configfs group's creation
time its name is not known (but instead set a bit later in
drivers/usb/gadget/configfs.c:function_make) and it is this name that
serves the purpose of the said name prefix. So instead of copying
a yet-unknown string a pointer to it is stored in struct fsg_lun.

Signed-off-by: Andrzej Pietrasiewicz <andrze...@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.p...@samsung.com>
---
 drivers/usb/gadget/f_mass_storage.c |  424 +++++++++++++++++++++++++++++++++--
 drivers/usb/gadget/f_mass_storage.h |   33 +++
 drivers/usb/gadget/storage_common.h |   20 ++-
 3 files changed, 454 insertions(+), 23 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c 
b/drivers/usb/gadget/f_mass_storage.c
index e2598f4..0bf7503 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -299,6 +299,7 @@ struct fsg_common {
        unsigned int            short_packet_received:1;
        unsigned int            bad_lun_okay:1;
        unsigned int            running:1;
+       unsigned int            sysfs:1;
 
        int                     thread_wakeup_needed;
        struct completion       thread_notifier;
@@ -2640,6 +2641,393 @@ static inline int fsg_num_buffers_validate(unsigned int 
fsg_num_buffers)
        return -EINVAL;
 }
 
+static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool 
zero)
+{
+       if (!common) {
+               common = kzalloc(sizeof(*common), GFP_KERNEL);
+               if (!common)
+                       return ERR_PTR(-ENOMEM);
+               common->free_storage_on_release = 1;
+       } else {
+               if (zero)
+                       memset(common, 0, sizeof(*common));
+               common->free_storage_on_release = 0;
+       }
+       init_rwsem(&common->filesem);
+       spin_lock_init(&common->lock);
+       kref_init(&common->ref);
+       init_completion(&common->thread_notifier);
+       init_waitqueue_head(&common->fsg_wait);
+       common->state = FSG_STATE_TERMINATED;
+
+       return common;
+}
+
+void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs)
+{
+       common->sysfs = sysfs;
+}
+
+static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n)
+{
+       if (buffhds) {
+               struct fsg_buffhd *bh = buffhds;
+               while (n--) {
+                       kfree(bh->buf);
+                       ++bh;
+               }
+               kfree(buffhds);
+       }
+}
+
+int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n)
+{
+       struct fsg_buffhd *bh, *new_buffhds;
+       int i, rc;
+
+       rc = fsg_num_buffers_validate(n);
+       if (rc != 0)
+               return rc;
+
+       new_buffhds = kcalloc(n, sizeof *(new_buffhds), GFP_KERNEL);
+       if (!new_buffhds)
+               return -ENOMEM;
+
+       /* Data buffers cyclic list */
+       bh = new_buffhds;
+       i = n;
+       goto buffhds_first_it;
+       do {
+               bh->next = bh + 1;
+               ++bh;
+buffhds_first_it:
+               bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
+               if (unlikely(!bh->buf))
+                       goto error_release;
+       } while (--i);
+       bh->next = new_buffhds;
+
+       _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
+       common->fsg_num_buffers = n;
+       common->buffhds = new_buffhds;
+
+       return 0;
+
+error_release:
+       _fsg_common_free_buffers(new_buffhds, n - i);
+
+       return -ENOMEM;
+}
+
+void fsg_common_free_buffers(struct fsg_common *common)
+{
+       _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
+       common->buffhds = NULL;
+}
+
+int fsg_common_set_nluns(struct fsg_common *common, int nluns)
+{
+       struct fsg_lun **curlun;
+
+       /* Find out how many LUNs there should be */
+       if (nluns < 1 || nluns > FSG_MAX_LUNS) {
+               pr_err("invalid number of LUNs: %u\n", nluns);
+               return -EINVAL;
+       }
+
+       curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+       if (unlikely(!curlun))
+               return -ENOMEM;
+
+       if (common->luns)
+               fsg_common_free_luns(common);
+
+       common->luns = curlun;
+       common->nluns = nluns;
+
+       pr_info("Number of LUNs=%d\n", common->nluns);
+
+       return 0;
+}
+
+void fsg_common_free_luns(struct fsg_common *common)
+{
+       fsg_common_remove_luns(common);
+       kfree(common->luns);
+       common->luns = NULL;
+}
+
+void fsg_common_set_ops(struct fsg_common *common,
+                       const struct fsg_operations *ops)
+{
+       common->ops = ops;
+}
+
+void fsg_common_set_private_data(struct fsg_common *common, void *priv)
+{
+       common->private_data = priv;
+}
+
+int fsg_common_set_cdev(struct fsg_common *common,
+                        struct usb_composite_dev *cdev, bool can_stall)
+{
+       struct usb_string *us;
+       int rc;
+
+       common->gadget = cdev->gadget;
+       common->ep0 = cdev->gadget->ep0;
+       common->ep0req = cdev->req;
+       common->cdev = cdev;
+
+       us = usb_gstrings_attach(cdev, fsg_strings_array,
+                                ARRAY_SIZE(fsg_strings));
+       if (IS_ERR(us)) {
+               rc = PTR_ERR(us);
+               return rc;
+       }
+       fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id;
+
+       /*
+        * Some peripheral controllers are known not to be able to
+        * halt bulk endpoints correctly.  If one of them is present,
+        * disable stalls.
+        */
+       common->can_stall = can_stall && !(gadget_is_at91(common->gadget));
+
+       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_cdrom;
+       rc = device_create_file(&lun->dev,
+                               lun->removable
+                             ? &dev_attr_file
+                             : &dev_attr_file_nonremovable);
+       if (rc)
+               goto error_removable;
+       rc = device_create_file(&lun->dev, &dev_attr_nofua);
+       if (rc)
+               goto error_nofua;
+
+       return 0;
+
+error_nofua:
+       device_remove_file(&lun->dev,
+                          lun->removable
+                        ? &dev_attr_file
+                        : &dev_attr_file_nonremovable);
+error_removable:
+       device_remove_file(&lun->dev,
+                          lun->cdrom
+                        ? &dev_attr_ro_cdrom
+                        : &dev_attr_ro);
+error_cdrom:
+       device_unregister(&lun->dev);
+       return rc;
+}
+
+static inline void fsg_common_remove_sysfs(struct fsg_lun *lun)
+{
+       device_remove_file(&lun->dev, &dev_attr_nofua);
+       device_remove_file(&lun->dev, lun->cdrom
+                          ? &dev_attr_ro_cdrom : &dev_attr_ro);
+       device_remove_file(&lun->dev, lun->removable
+                          ? &dev_attr_file : &dev_attr_file_nonremovable);
+}
+
+void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs)
+{
+       if (sysfs) {
+               fsg_common_remove_sysfs(lun);
+               device_unregister(&lun->dev);
+       }
+       fsg_lun_close(lun);
+       kfree(lun->name);
+       kfree(lun);
+}
+
+void _fsg_common_remove_luns(struct fsg_common *common, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i)
+               if (common->luns[i]) {
+                       fsg_common_remove_lun(common->luns[i], common->sysfs);
+                       common->luns[i] = NULL;
+               }
+}
+
+void fsg_common_remove_luns(struct fsg_common *common)
+{
+       _fsg_common_remove_luns(common, common->nluns);
+}
+
+#define MAX_LUN_NAME_LEN 80
+
+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;
+       int rc = -ENOMEM;
+       int name_len;
+
+       if (!common->nluns || !common->luns)
+               return -ENODEV;
+
+       if (common->luns[id])
+               return -EBUSY;
+
+       name_len = strlen(name) + 1;
+       if (name_len > MAX_LUN_NAME_LEN)
+               return -ENAMETOOLONG;
+
+       lun = kzalloc(sizeof(*lun), GFP_KERNEL);
+       if (!lun)
+               return -ENOMEM;
+
+       lun->name = kstrndup(name, name_len, GFP_KERNEL);
+       if (!lun->name)
+               goto error_name;
+       lun->name_pfx = name_pfx;
+
+       lun->cdrom = !!cfg->cdrom;
+       lun->ro = cfg->cdrom || cfg->ro;
+       lun->initially_ro = lun->ro;
+       lun->removable = !!cfg->removable;
+
+       common->luns[id] = lun;
+
+       if (common->sysfs) {
+               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);
+
+               rc = fsg_common_add_sysfs(common, lun);
+               if (rc) {
+                       pr_info("failed to register LUN%d: %d\n", id, rc);
+                       goto error_sysfs;
+               }
+       }
+
+       if (cfg->filename) {
+               rc = fsg_lun_open(lun, cfg->filename);
+               if (rc)
+                       goto error_lun;
+       } else if (!lun->removable) {
+               pr_err("no file given for LUN%d\n", id);
+               rc = -EINVAL;
+               goto error_lun;
+       }
+
+       pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+       {
+               char *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);
+error_sysfs:
+       common->luns[id] = NULL;
+       kfree(lun->name);
+error_name:
+       kfree(lun);
+       return rc;
+}
+
+int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg)
+{
+       char buf[40]; /* enough for 2^128 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;
+}
+
+void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
+                                  const char *pn)
+{
+       int i;
+
+       /* Prepare inquiryString */
+       i = get_default_bcdDevice();
+       snprintf(common->inquiry_string, sizeof(common->inquiry_string),
+                "%-8s%-16s%04x", vn ?: "Linux",
+                /* Assume product name dependent on the first LUN */
+                pn ?: ((*common->luns)->cdrom
+                    ? "File-CD Gadget"
+                    : "File-Stor Gadget"),
+                i);
+}
+
+int fsg_common_run_thread(struct fsg_common *common)
+{
+       common->state = FSG_STATE_IDLE;
+       /* Tell the thread to start working */
+       common->thread_task =
+               kthread_create(fsg_main_thread, common, "file-storage");
+       if (IS_ERR(common->thread_task)) {
+               common->state = FSG_STATE_TERMINATED;
+               return PTR_ERR(common->thread_task);
+       }
+
+       DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+
+       wake_up_process(common->thread_task);
+
+       return 0;
+}
+
 struct fsg_common *fsg_common_init(struct fsg_common *common,
                                   struct usb_composite_dev *cdev,
                                   struct fsg_config *cfg)
@@ -2673,6 +3061,8 @@ struct fsg_common *fsg_common_init(struct fsg_common 
*common,
                memset(common, 0, sizeof *common);
                common->free_storage_on_release = 0;
        }
+       common->sysfs = true;
+       common->state = FSG_STATE_IDLE;
 
        common->fsg_num_buffers = cfg->fsg_num_buffers;
        common->buffhds = kcalloc(common->fsg_num_buffers,
@@ -2723,6 +3113,12 @@ struct fsg_common *fsg_common_init(struct fsg_common 
*common,
                }
                *curlun_it = curlun;
 
+               curlun->name = kzalloc(MAX_LUN_NAME_LEN, GFP_KERNEL);
+               if (!curlun->name) {
+                       rc = -ENOMEM;
+                       common->nluns = i;
+                       goto error_release;
+               }
                curlun->cdrom = !!lcfg->cdrom;
                curlun->ro = lcfg->cdrom || lcfg->ro;
                curlun->initially_ro = curlun->ro;
@@ -2732,6 +3128,7 @@ struct fsg_common *fsg_common_init(struct fsg_common 
*common,
                /* curlun->dev.driver = &fsg_driver.driver; XXX */
                dev_set_drvdata(&curlun->dev, &common->filesem);
                dev_set_name(&curlun->dev, "lun%d", i);
+               strlcpy(curlun->name, dev_name(&curlun->dev), MAX_LUN_NAME_LEN);
 
                rc = device_register(&curlun->dev);
                if (rc) {
@@ -2878,32 +3275,21 @@ static void fsg_common_release(struct kref *ref)
                        struct fsg_lun *lun = *lun_it;
                        if (!lun)
                                continue;
-                       device_remove_file(&lun->dev, &dev_attr_nofua);
-                       device_remove_file(&lun->dev,
-                                          lun->cdrom
-                                        ? &dev_attr_ro_cdrom
-                                        : &dev_attr_ro);
-                       device_remove_file(&lun->dev,
-                                          lun->removable
-                                        ? &dev_attr_file
-                                        : &dev_attr_file_nonremovable);
+                       if (common->sysfs)
+                               fsg_common_remove_sysfs(lun);
                        fsg_lun_close(lun);
-                       device_unregister(&lun->dev);
+                       if (common->sysfs)
+                               device_unregister(&lun->dev);
+                       kfree(lun->name);
                        kfree(lun);
                }
 
                kfree(common->luns);
        }
 
-       {
-               struct fsg_buffhd *bh = common->buffhds;
-               unsigned i = common->fsg_num_buffers;
-               do {
-                       kfree(bh->buf);
-               } while (++bh, --i);
-       }
-
-       kfree(common->buffhds);
+       if (likely(common->buffhds))
+               _fsg_common_free_buffers(common->buffhds,
+                                        common->fsg_num_buffers);
        if (common->free_storage_on_release)
                kfree(common);
 }
diff --git a/drivers/usb/gadget/f_mass_storage.h 
b/drivers/usb/gadget/f_mass_storage.h
index b64761d..4445e82 100644
--- a/drivers/usb/gadget/f_mass_storage.h
+++ b/drivers/usb/gadget/f_mass_storage.h
@@ -102,6 +102,39 @@ struct fsg_common *fsg_common_init(struct fsg_common 
*common,
                                   struct usb_composite_dev *cdev,
                                   struct fsg_config *cfg);
 
+void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
+
+int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);
+
+void fsg_common_free_buffers(struct fsg_common *common);
+
+int fsg_common_set_nluns(struct fsg_common *common, int nluns);
+
+void fsg_common_free_luns(struct fsg_common *common);
+
+void fsg_common_set_ops(struct fsg_common *common,
+                       const struct fsg_operations *ops);
+
+void fsg_common_set_private_data(struct fsg_common *common, void *priv);
+
+int fsg_common_set_cdev(struct fsg_common *common,
+                       struct usb_composite_dev *cdev, bool can_stall);
+
+void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs);
+
+void fsg_common_remove_luns(struct fsg_common *common);
+
+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_common_set_inquiry_string(struct fsg_common *common, const char *vn,
+                                  const char *pn);
+
+int fsg_common_run_thread(struct fsg_common *common);
+
 void fsg_config_from_params(struct fsg_config *cfg,
                            const struct fsg_module_parameters *params,
                            unsigned int fsg_num_buffers);
diff --git a/drivers/usb/gadget/storage_common.h 
b/drivers/usb/gadget/storage_common.h
index 1fcda2b..9955477 100644
--- a/drivers/usb/gadget/storage_common.h
+++ b/drivers/usb/gadget/storage_common.h
@@ -17,10 +17,20 @@
 #define VLDBG(lun, fmt, args...) do { } while (0)
 #endif /* VERBOSE_DEBUG */
 
-#define LDBG(lun, fmt, args...)   dev_dbg(&(lun)->dev, fmt, ## args)
-#define LERROR(lun, fmt, args...) dev_err(&(lun)->dev, fmt, ## args)
-#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
-#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
+#define _LMSG(func, lun, fmt, args...)                                 \
+       do {                                                            \
+               if ((lun)->name_pfx && *(lun)->name_pfx)                \
+                       func("%s/%s: " fmt, *(lun)->name_pfx,           \
+                                (lun)->name, ## args);                 \
+               else                                                    \
+                       func("%s: " fmt, (lun)->name, ## args);         \
+       } while (0)
+
+#define LDBG(lun, fmt, args...)                _LMSG(pr_debug, lun, fmt, ## 
args)
+#define LERROR(lun, fmt, args...)      _LMSG(pr_err, lun, fmt, ## args)
+#define LWARN(lun, fmt, args...)       _LMSG(pr_warn, lun, fmt, ## args)
+#define LINFO(lun, fmt, args...)       _LMSG(pr_info, lun, fmt, ## args)
+
 
 #ifdef DUMP_MSGS
 
@@ -100,6 +110,8 @@ struct fsg_lun {
                                                       of bound block device */
        unsigned int    blksize; /* logical block size of bound block device */
        struct device   dev;
+       char            *name; /* "function.name/lun.name" */
+       const char      **name_pfx;
 };
 
 static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to