aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2013-10-09 04:06:05 -0400
committerFelipe Balbi <balbi@ti.com>2013-10-10 11:24:27 -0400
commitef0aa4b92cf10a7684135c61dc406398308b328f (patch)
treed2147f3c87db29e438197dcfab9d7338e190d765 /drivers/usb
parent864328ef8e735403f85b768284001a4187d6868f (diff)
usb: gadget: f_mass_storage: add configfs support
From this commit on f_mass_storage is available through configfs. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/f_mass_storage.c360
-rw-r--r--drivers/usb/gadget/f_mass_storage.h17
3 files changed, 388 insertions, 0 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7d64e474c48b..bc5dea2f26e2 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -668,6 +668,17 @@ config USB_CONFIGFS_PHONET
668 help 668 help
669 The Phonet protocol implementation for USB device. 669 The Phonet protocol implementation for USB device.
670 670
671config USB_CONFIGFS_MASS_STORAGE
672 boolean "Mass storage"
673 depends on USB_CONFIGFS
674 select USB_U_MS
675 select USB_F_MASS_STORAGE
676 help
677 The Mass Storage Gadget acts as a USB Mass Storage disk drive.
678 As its storage repository it can use a regular file or a block
679 device (in much the same way as the "loop" device driver),
680 specified as a module parameter or sysfs option.
681
671config USB_ZERO 682config USB_ZERO
672 tristate "Gadget Zero (DEVELOPMENT)" 683 tristate "Gadget Zero (DEVELOPMENT)"
673 select USB_LIBCOMPOSITE 684 select USB_LIBCOMPOSITE
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index d80be5f0e6d2..00d3687594bb 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -220,6 +220,7 @@
220#include <linux/usb/composite.h> 220#include <linux/usb/composite.h>
221 221
222#include "gadget_chips.h" 222#include "gadget_chips.h"
223#include "configfs.h"
223 224
224 225
225/*------------------------------------------------------------------------*/ 226/*------------------------------------------------------------------------*/
@@ -3295,6 +3296,342 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
3295 3296
3296#else 3297#else
3297 3298
3299static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
3300{
3301 return container_of(to_config_group(item), struct fsg_lun_opts, group);
3302}
3303
3304static inline struct fsg_opts *to_fsg_opts(struct config_item *item)
3305{
3306 return container_of(to_config_group(item), struct fsg_opts,
3307 func_inst.group);
3308}
3309
3310CONFIGFS_ATTR_STRUCT(fsg_lun_opts);
3311CONFIGFS_ATTR_OPS(fsg_lun_opts);
3312
3313static void fsg_lun_attr_release(struct config_item *item)
3314{
3315 struct fsg_lun_opts *lun_opts;
3316
3317 lun_opts = to_fsg_lun_opts(item);
3318 kfree(lun_opts);
3319}
3320
3321static struct configfs_item_operations fsg_lun_item_ops = {
3322 .release = fsg_lun_attr_release,
3323 .show_attribute = fsg_lun_opts_attr_show,
3324 .store_attribute = fsg_lun_opts_attr_store,
3325};
3326
3327static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page)
3328{
3329 struct fsg_opts *fsg_opts;
3330
3331 fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
3332
3333 return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page);
3334}
3335
3336static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts,
3337 const char *page, size_t len)
3338{
3339 struct fsg_opts *fsg_opts;
3340
3341 fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
3342
3343 return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len);
3344}
3345
3346static struct fsg_lun_opts_attribute fsg_lun_opts_file =
3347 __CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show,
3348 fsg_lun_opts_file_store);
3349
3350static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page)
3351{
3352 return fsg_show_ro(opts->lun, page);
3353}
3354
3355static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts,
3356 const char *page, size_t len)
3357{
3358 struct fsg_opts *fsg_opts;
3359
3360 fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
3361
3362 return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len);
3363}
3364
3365static struct fsg_lun_opts_attribute fsg_lun_opts_ro =
3366 __CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show,
3367 fsg_lun_opts_ro_store);
3368
3369static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts,
3370 char *page)
3371{
3372 return fsg_show_removable(opts->lun, page);
3373}
3374
3375static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts,
3376 const char *page, size_t len)
3377{
3378 return fsg_store_removable(opts->lun, page, len);
3379}
3380
3381static struct fsg_lun_opts_attribute fsg_lun_opts_removable =
3382 __CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR,
3383 fsg_lun_opts_removable_show,
3384 fsg_lun_opts_removable_store);
3385
3386static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page)
3387{
3388 return fsg_show_cdrom(opts->lun, page);
3389}
3390
3391static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts,
3392 const char *page, size_t len)
3393{
3394 return fsg_store_cdrom(opts->lun, page, len);
3395}
3396
3397static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom =
3398 __CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show,
3399 fsg_lun_opts_cdrom_store);
3400
3401static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page)
3402{
3403 return fsg_show_nofua(opts->lun, page);
3404}
3405
3406static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts,
3407 const char *page, size_t len)
3408{
3409 return fsg_store_nofua(opts->lun, page, len);
3410}
3411
3412static struct fsg_lun_opts_attribute fsg_lun_opts_nofua =
3413 __CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show,
3414 fsg_lun_opts_nofua_store);
3415
3416static struct configfs_attribute *fsg_lun_attrs[] = {
3417 &fsg_lun_opts_file.attr,
3418 &fsg_lun_opts_ro.attr,
3419 &fsg_lun_opts_removable.attr,
3420 &fsg_lun_opts_cdrom.attr,
3421 &fsg_lun_opts_nofua.attr,
3422 NULL,
3423};
3424
3425static struct config_item_type fsg_lun_type = {
3426 .ct_item_ops = &fsg_lun_item_ops,
3427 .ct_attrs = fsg_lun_attrs,
3428 .ct_owner = THIS_MODULE,
3429};
3430
3431#define MAX_NAME_LEN 40
3432
3433static struct config_group *fsg_lun_make(struct config_group *group,
3434 const char *name)
3435{
3436 struct fsg_lun_opts *opts;
3437 struct fsg_opts *fsg_opts;
3438 struct fsg_lun_config config;
3439 char *num_str;
3440 u8 num;
3441 int ret;
3442
3443 num_str = strchr(name, '.');
3444 if (!num_str) {
3445 pr_err("Unable to locate . in LUN.NUMBER\n");
3446 return ERR_PTR(-EINVAL);
3447 }
3448 num_str++;
3449
3450 ret = kstrtou8(num_str, 0, &num);
3451 if (ret)
3452 return ERR_PTR(ret);
3453
3454 fsg_opts = to_fsg_opts(&group->cg_item);
3455 if (num >= FSG_MAX_LUNS)
3456 return ERR_PTR(-ENODEV);
3457 mutex_lock(&fsg_opts->lock);
3458 if (fsg_opts->refcnt || fsg_opts->common->luns[num]) {
3459 ret = -EBUSY;
3460 goto out;
3461 }
3462
3463 opts = kzalloc(sizeof(*opts), GFP_KERNEL);
3464 if (!opts) {
3465 ret = -ENOMEM;
3466 goto out;
3467 }
3468
3469 memset(&config, 0, sizeof(config));
3470 config.removable = true;
3471
3472
3473 ret = fsg_common_create_lun(fsg_opts->common, &config, num, name,
3474 (const char **)&group->cg_item.ci_name);
3475 if (ret) {
3476 kfree(opts);
3477 goto out;
3478 }
3479 opts->lun = fsg_opts->common->luns[num];
3480 opts->lun_id = num;
3481 mutex_unlock(&fsg_opts->lock);
3482
3483 config_group_init_type_name(&opts->group, name, &fsg_lun_type);
3484
3485 return &opts->group;
3486out:
3487 mutex_unlock(&fsg_opts->lock);
3488 return ERR_PTR(ret);
3489}
3490
3491static void fsg_lun_drop(struct config_group *group, struct config_item *item)
3492{
3493 struct fsg_lun_opts *lun_opts;
3494 struct fsg_opts *fsg_opts;
3495
3496 lun_opts = to_fsg_lun_opts(item);
3497 fsg_opts = to_fsg_opts(&group->cg_item);
3498
3499 mutex_lock(&fsg_opts->lock);
3500 if (fsg_opts->refcnt) {
3501 struct config_item *gadget;
3502
3503 gadget = group->cg_item.ci_parent->ci_parent;
3504 unregister_gadget_item(gadget);
3505 }
3506
3507 fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs);
3508 fsg_opts->common->luns[lun_opts->lun_id] = NULL;
3509 lun_opts->lun_id = 0;
3510 mutex_unlock(&fsg_opts->lock);
3511
3512 config_item_put(item);
3513}
3514
3515CONFIGFS_ATTR_STRUCT(fsg_opts);
3516CONFIGFS_ATTR_OPS(fsg_opts);
3517
3518static void fsg_attr_release(struct config_item *item)
3519{
3520 struct fsg_opts *opts = to_fsg_opts(item);
3521
3522 usb_put_function_instance(&opts->func_inst);
3523}
3524
3525static struct configfs_item_operations fsg_item_ops = {
3526 .release = fsg_attr_release,
3527 .show_attribute = fsg_opts_attr_show,
3528 .store_attribute = fsg_opts_attr_store,
3529};
3530
3531static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page)
3532{
3533 int result;
3534
3535 mutex_lock(&opts->lock);
3536 result = sprintf(page, "%d", opts->common->can_stall);
3537 mutex_unlock(&opts->lock);
3538
3539 return result;
3540}
3541
3542static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page,
3543 size_t len)
3544{
3545 int ret;
3546 u8 num;
3547
3548 mutex_lock(&opts->lock);
3549 if (opts->refcnt) {
3550 ret = -EBUSY;
3551 goto end;
3552 }
3553 ret = kstrtou8(page, 0, &num);
3554 if (ret)
3555 goto end;
3556
3557 opts->common->can_stall = num != 0;
3558 ret = len;
3559
3560end:
3561 mutex_unlock(&opts->lock);
3562 return ret;
3563}
3564
3565static struct fsg_opts_attribute fsg_opts_stall =
3566 __CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show,
3567 fsg_opts_stall_store);
3568
3569#ifdef CONFIG_USB_GADGET_DEBUG_FILES
3570static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page)
3571{
3572 int result;
3573
3574 mutex_lock(&opts->lock);
3575 result = sprintf(page, "%d", opts->common->fsg_num_buffers);
3576 mutex_unlock(&opts->lock);
3577
3578 return result;
3579}
3580
3581static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts,
3582 const char *page, size_t len)
3583{
3584 int ret;
3585 u8 num;
3586
3587 mutex_lock(&opts->lock);
3588 if (opts->refcnt) {
3589 ret = -EBUSY;
3590 goto end;
3591 }
3592 ret = kstrtou8(page, 0, &num);
3593 if (ret)
3594 goto end;
3595
3596 ret = fsg_num_buffers_validate(num);
3597 if (ret)
3598 goto end;
3599
3600 fsg_common_set_num_buffers(opts->common, num);
3601 ret = len;
3602
3603end:
3604 mutex_unlock(&opts->lock);
3605 return ret;
3606}
3607
3608static struct fsg_opts_attribute fsg_opts_num_buffers =
3609 __CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR,
3610 fsg_opts_num_buffers_show,
3611 fsg_opts_num_buffers_store);
3612
3613#endif
3614
3615static struct configfs_attribute *fsg_attrs[] = {
3616 &fsg_opts_stall.attr,
3617#ifdef CONFIG_USB_GADGET_DEBUG_FILES
3618 &fsg_opts_num_buffers.attr,
3619#endif
3620 NULL,
3621};
3622
3623static struct configfs_group_operations fsg_group_ops = {
3624 .make_group = fsg_lun_make,
3625 .drop_item = fsg_lun_drop,
3626};
3627
3628static struct config_item_type fsg_func_type = {
3629 .ct_item_ops = &fsg_item_ops,
3630 .ct_group_ops = &fsg_group_ops,
3631 .ct_attrs = fsg_attrs,
3632 .ct_owner = THIS_MODULE,
3633};
3634
3298static void fsg_free_inst(struct usb_function_instance *fi) 3635static void fsg_free_inst(struct usb_function_instance *fi)
3299{ 3636{
3300 struct fsg_opts *opts; 3637 struct fsg_opts *opts;
@@ -3307,11 +3644,13 @@ static void fsg_free_inst(struct usb_function_instance *fi)
3307static struct usb_function_instance *fsg_alloc_inst(void) 3644static struct usb_function_instance *fsg_alloc_inst(void)
3308{ 3645{
3309 struct fsg_opts *opts; 3646 struct fsg_opts *opts;
3647 struct fsg_lun_config config;
3310 int rc; 3648 int rc;
3311 3649
3312 opts = kzalloc(sizeof(*opts), GFP_KERNEL); 3650 opts = kzalloc(sizeof(*opts), GFP_KERNEL);
3313 if (!opts) 3651 if (!opts)
3314 return ERR_PTR(-ENOMEM); 3652 return ERR_PTR(-ENOMEM);
3653 mutex_init(&opts->lock);
3315 opts->func_inst.free_func_inst = fsg_free_inst; 3654 opts->func_inst.free_func_inst = fsg_free_inst;
3316 opts->common = fsg_common_setup(opts->common, false); 3655 opts->common = fsg_common_setup(opts->common, false);
3317 if (IS_ERR(opts->common)) { 3656 if (IS_ERR(opts->common)) {
@@ -3329,6 +3668,18 @@ static struct usb_function_instance *fsg_alloc_inst(void)
3329 3668
3330 pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); 3669 pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
3331 3670
3671 memset(&config, 0, sizeof(config));
3672 config.removable = true;
3673 rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0",
3674 (const char **)&opts->func_inst.group.cg_item.ci_name);
3675 opts->lun0.lun = opts->common->luns[0];
3676 opts->lun0.lun_id = 0;
3677 config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
3678 opts->default_groups[0] = &opts->lun0.group;
3679 opts->func_inst.group.default_groups = opts->default_groups;
3680
3681 config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type);
3682
3332 return &opts->func_inst; 3683 return &opts->func_inst;
3333 3684
3334release_luns: 3685release_luns:
@@ -3341,8 +3692,14 @@ release_opts:
3341static void fsg_free(struct usb_function *f) 3692static void fsg_free(struct usb_function *f)
3342{ 3693{
3343 struct fsg_dev *fsg; 3694 struct fsg_dev *fsg;
3695 struct fsg_opts *opts;
3344 3696
3345 fsg = container_of(f, struct fsg_dev, function); 3697 fsg = container_of(f, struct fsg_dev, function);
3698 opts = container_of(f->fi, struct fsg_opts, func_inst);
3699
3700 mutex_lock(&opts->lock);
3701 opts->refcnt--;
3702 mutex_unlock(&opts->lock);
3346 3703
3347 kfree(fsg); 3704 kfree(fsg);
3348} 3705}
@@ -3357,6 +3714,9 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
3357 if (unlikely(!fsg)) 3714 if (unlikely(!fsg))
3358 return ERR_PTR(-ENOMEM); 3715 return ERR_PTR(-ENOMEM);
3359 3716
3717 mutex_lock(&opts->lock);
3718 opts->refcnt++;
3719 mutex_unlock(&opts->lock);
3360 fsg->function.name = FSG_DRIVER_DESC; 3720 fsg->function.name = FSG_DRIVER_DESC;
3361 fsg->function.bind = fsg_bind; 3721 fsg->function.bind = fsg_bind;
3362 fsg->function.unbind = fsg_unbind; 3722 fsg->function.unbind = fsg_unbind;
diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h
index b53cf8c9189e..7d421d2ac3c9 100644
--- a/drivers/usb/gadget/f_mass_storage.h
+++ b/drivers/usb/gadget/f_mass_storage.h
@@ -71,10 +71,27 @@ struct fsg_operations {
71 int (*thread_exits)(struct fsg_common *common); 71 int (*thread_exits)(struct fsg_common *common);
72}; 72};
73 73
74struct fsg_lun_opts {
75 struct config_group group;
76 struct fsg_lun *lun;
77 int lun_id;
78};
79
74struct fsg_opts { 80struct fsg_opts {
75 struct fsg_common *common; 81 struct fsg_common *common;
76 struct usb_function_instance func_inst; 82 struct usb_function_instance func_inst;
83 struct fsg_lun_opts lun0;
84 struct config_group *default_groups[2];
77 bool no_configfs; /* for legacy gadgets */ 85 bool no_configfs; /* for legacy gadgets */
86
87 /*
88 * Read/write access to configfs attributes is handled by configfs.
89 *
90 * This is to protect the data from concurrent access by read/write
91 * and create symlink/remove symlink.
92 */
93 struct mutex lock;
94 int refcnt;
78}; 95};
79 96
80struct fsg_lun_config { 97struct fsg_lun_config {