diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2013-10-09 04:06:05 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-10-10 11:24:27 -0400 |
commit | ef0aa4b92cf10a7684135c61dc406398308b328f (patch) | |
tree | d2147f3c87db29e438197dcfab9d7338e190d765 /drivers/usb | |
parent | 864328ef8e735403f85b768284001a4187d6868f (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/Kconfig | 11 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 360 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.h | 17 |
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 | ||
671 | config 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 | |||
671 | config USB_ZERO | 682 | config 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 | ||
3299 | static 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 | |||
3304 | static 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 | |||
3310 | CONFIGFS_ATTR_STRUCT(fsg_lun_opts); | ||
3311 | CONFIGFS_ATTR_OPS(fsg_lun_opts); | ||
3312 | |||
3313 | static 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 | |||
3321 | static 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 | |||
3327 | static 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 | |||
3336 | static 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 | |||
3346 | static 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 | |||
3350 | static 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 | |||
3355 | static 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 | |||
3365 | static 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 | |||
3369 | static 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 | |||
3375 | static 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 | |||
3381 | static 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 | |||
3386 | static 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 | |||
3391 | static 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 | |||
3397 | static 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 | |||
3401 | static 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 | |||
3406 | static 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 | |||
3412 | static 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 | |||
3416 | static 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 | |||
3425 | static 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 | |||
3433 | static 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; | ||
3486 | out: | ||
3487 | mutex_unlock(&fsg_opts->lock); | ||
3488 | return ERR_PTR(ret); | ||
3489 | } | ||
3490 | |||
3491 | static 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 | |||
3515 | CONFIGFS_ATTR_STRUCT(fsg_opts); | ||
3516 | CONFIGFS_ATTR_OPS(fsg_opts); | ||
3517 | |||
3518 | static 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 | |||
3525 | static 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 | |||
3531 | static 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 | |||
3542 | static 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 | |||
3560 | end: | ||
3561 | mutex_unlock(&opts->lock); | ||
3562 | return ret; | ||
3563 | } | ||
3564 | |||
3565 | static 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 | ||
3570 | static 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 | |||
3581 | static 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 | |||
3603 | end: | ||
3604 | mutex_unlock(&opts->lock); | ||
3605 | return ret; | ||
3606 | } | ||
3607 | |||
3608 | static 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 | |||
3615 | static 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 | |||
3623 | static struct configfs_group_operations fsg_group_ops = { | ||
3624 | .make_group = fsg_lun_make, | ||
3625 | .drop_item = fsg_lun_drop, | ||
3626 | }; | ||
3627 | |||
3628 | static 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 | |||
3298 | static void fsg_free_inst(struct usb_function_instance *fi) | 3635 | static 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) | |||
3307 | static struct usb_function_instance *fsg_alloc_inst(void) | 3644 | static 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 | ||
3334 | release_luns: | 3685 | release_luns: |
@@ -3341,8 +3692,14 @@ release_opts: | |||
3341 | static void fsg_free(struct usb_function *f) | 3692 | static 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 | ||
74 | struct fsg_lun_opts { | ||
75 | struct config_group group; | ||
76 | struct fsg_lun *lun; | ||
77 | int lun_id; | ||
78 | }; | ||
79 | |||
74 | struct fsg_opts { | 80 | struct 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 | ||
80 | struct fsg_lun_config { | 97 | struct fsg_lun_config { |