Signed-off-by: Andrzej Pietrasiewicz <[email protected]>
Signed-off-by: Kyungmin Park <[email protected]>
---
drivers/usb/gadget/Kconfig | 4 +
drivers/usb/gadget/Makefile | 3 +
drivers/usb/gadget/f_mass_storage.c | 825 +++++++++++++++++------------------
drivers/usb/gadget/f_mass_storage.h | 99 +++++
drivers/usb/gadget/storage_common.c | 175 +++++---
drivers/usb/gadget/storage_common.h | 43 ++
6 files changed, 648 insertions(+), 501 deletions(-)
create mode 100644 drivers/usb/gadget/f_mass_storage.h
create mode 100644 drivers/usb/gadget/storage_common.h
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 80ab9a5..f142db3 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -501,6 +501,9 @@ config USB_LIBCOMPOSITE
tristate
depends on USB_GADGET
+config USB_F_MASS_STORAGE
+ tristate
+
choice
tristate "USB Gadget Drivers"
default USB_ETH
@@ -524,6 +527,7 @@ choice
config USB_FG
tristate "USB Functions Gadget"
+ select USB_F_MASS_STORAGE
depends on CONFIGFS_FS
help
USB Functions Gadget is a device which aggregates a number of
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 378296b..536f4d6 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -75,3 +75,6 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
+
+# USB Functions
+obj-$(CONFIG_USB_F_MASS_STORAGE) += f_mass_storage.o
\ No newline at end of file
diff --git a/drivers/usb/gadget/f_mass_storage.c
b/drivers/usb/gadget/f_mass_storage.c
index 5d027b3..a558f32 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -213,12 +213,14 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/freezer.h>
+#include <linux/module.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include "gadget_chips.h"
+#include "usb_functions.h"
/*------------------------------------------------------------------------*/
@@ -229,124 +231,11 @@
static const char fsg_string_interface[] = "Mass Storage";
#include "storage_common.c"
-
+#include "f_mass_storage.h"
/*-------------------------------------------------------------------------*/
-struct fsg_dev;
-struct fsg_common;
-
-/* FSF callback functions */
-struct fsg_operations {
- /*
- * Callback function to call when thread exits. If no
- * callback is set or it returns value lower then zero MSF
- * will force eject all LUNs it operates on (including those
- * marked as non-removable or with prevent_medium_removal flag
- * set).
- */
- int (*thread_exits)(struct fsg_common *common);
-
- /*
- * Called prior to ejection. Negative return means error,
- * zero means to continue with ejection, positive means not to
- * eject.
- */
- int (*pre_eject)(struct fsg_common *common,
- struct fsg_lun *lun, int num);
- /*
- * Called after ejection. Negative return means error, zero
- * or positive is just a success.
- */
- int (*post_eject)(struct fsg_common *common,
- struct fsg_lun *lun, int num);
-};
-
-/* Data shared by all the FSG instances. */
-struct fsg_common {
- struct usb_gadget *gadget;
- struct usb_composite_dev *cdev;
- struct fsg_dev *fsg, *new_fsg;
- wait_queue_head_t fsg_wait;
-
- /* filesem protects: backing files in use */
- struct rw_semaphore filesem;
-
- /* lock protects: state, all the req_busy's */
- spinlock_t lock;
-
- struct usb_ep *ep0; /* Copy of gadget->ep0 */
- struct usb_request *ep0req; /* Copy of cdev->req */
- unsigned int ep0_req_tag;
-
- struct fsg_buffhd *next_buffhd_to_fill;
- struct fsg_buffhd *next_buffhd_to_drain;
- struct fsg_buffhd *buffhds;
-
- int cmnd_size;
- u8 cmnd[MAX_COMMAND_SIZE];
-
- unsigned int nluns;
- unsigned int lun;
- struct fsg_lun *luns;
- struct fsg_lun *curlun;
-
- unsigned int bulk_out_maxpacket;
- enum fsg_state state; /* For exception handling */
- unsigned int exception_req_tag;
-
- enum data_direction data_dir;
- u32 data_size;
- u32 data_size_from_cmnd;
- u32 tag;
- u32 residue;
- u32 usb_amount_left;
-
- unsigned int can_stall:1;
- unsigned int free_storage_on_release:1;
- unsigned int phase_error:1;
- unsigned int short_packet_received:1;
- unsigned int bad_lun_okay:1;
- unsigned int running:1;
-
- int thread_wakeup_needed;
- struct completion thread_notifier;
- struct task_struct *thread_task;
-
- /* Callback functions. */
- const struct fsg_operations *ops;
- /* Gadget's private data. */
- void *private_data;
-
- /*
- * Vendor (8 chars), product (16 chars), release (4
- * hexadecimal digits) and NUL byte
- */
- char inquiry_string[8 + 16 + 4 + 1];
-
- struct kref ref;
-};
-
-struct fsg_config {
- unsigned nluns;
- struct fsg_lun_config {
- const char *filename;
- char ro;
- char removable;
- char cdrom;
- char nofua;
- } luns[FSG_MAX_LUNS];
-
- /* Callback functions. */
- const struct fsg_operations *ops;
- /* Gadget's private data. */
- void *private_data;
-
- const char *vendor_name; /* 8 characters or less */
- const char *product_name; /* 16 characters or less */
-
- char can_stall;
-};
+static unsigned long msg_registered;
struct fsg_dev {
struct usb_function function;
@@ -1374,26 +1263,13 @@ static int do_start_stop(struct fsg_common *common)
if (!loej)
return 0;
- /* Simulate an unload/eject */
- if (common->ops && common->ops->pre_eject) {
- int r = common->ops->pre_eject(common, curlun,
- curlun - common->luns);
- if (unlikely(r < 0))
- return r;
- else if (r)
- return 0;
- }
-
up_read(&common->filesem);
down_write(&common->filesem);
fsg_lun_close(curlun);
up_write(&common->filesem);
down_read(&common->filesem);
- return common->ops && common->ops->post_eject
- ? min(0, common->ops->post_eject(common, curlun,
- curlun - common->luns))
- : 0;
+ return 0;
}
static int do_prevent_allow(struct fsg_common *common)
@@ -2196,9 +2072,23 @@ static int received_cbw(struct fsg_dev *fsg, struct
fsg_buffhd *bh)
if (common->data_size == 0)
common->data_dir = DATA_DIR_NONE;
common->lun = cbw->Lun;
- if (common->lun >= 0 && common->lun < common->nluns)
- common->curlun = &common->luns[common->lun];
- else
+ if (common->lun >= 0 && common->lun < common->nluns) {
+ struct config_item *it;
+
+ mutex_lock(&common->group.group.cg_subsys->su_mutex);
+ list_for_each_entry(it, &common->group.group.cg_children,
+ ci_entry) {
+ struct fsg_lun *lun;
+
+ lun = to_fsg_lun(it);
+ if (lun->n_lun == common->lun) {
+ common->curlun = lun;
+
+ break;
+ }
+ }
+ mutex_unlock(&common->group.group.cg_subsys->su_mutex);
+ } else
common->curlun = NULL;
common->tag = cbw->Tag;
return 0;
@@ -2258,6 +2148,7 @@ static int alloc_request(struct fsg_common *common,
struct usb_ep *ep,
/* Reset interface setting and re-init endpoint state (toggle etc). */
static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
{
+ struct config_item *item;
struct fsg_dev *fsg;
int i, rc = 0;
@@ -2342,8 +2233,14 @@ reset:
}
common->running = 1;
- for (i = 0; i < common->nluns; ++i)
- common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+ mutex_lock(&common->group.group.cg_subsys->su_mutex);
+ list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+ struct fsg_lun *lun;
+
+ lun = to_fsg_lun(item);
+ lun->unit_attention_data = SS_RESET_OCCURRED;
+ }
+ mutex_unlock(&common->group.group.cg_subsys->su_mutex);
return rc;
}
@@ -2374,7 +2271,6 @@ static void handle_exception(struct fsg_common *common)
int i;
struct fsg_buffhd *bh;
enum fsg_state old_state;
- struct fsg_lun *curlun;
unsigned int exception_req_tag;
/*
@@ -2442,14 +2338,21 @@ static void handle_exception(struct fsg_common *common)
if (old_state == FSG_STATE_ABORT_BULK_OUT)
common->state = FSG_STATE_STATUS_PHASE;
else {
- for (i = 0; i < common->nluns; ++i) {
- curlun = &common->luns[i];
+ struct config_item *it;
+
+ mutex_lock(&common->group.group.cg_subsys->su_mutex);
+ list_for_each_entry(it, &common->group.group.cg_children,
+ ci_entry) {
+ struct fsg_lun *curlun;
+
+ curlun = to_fsg_lun(it);
curlun->prevent_medium_removal = 0;
curlun->sense_data = SS_NO_SENSE;
curlun->unit_attention_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
curlun->info_valid = 0;
}
+ mutex_unlock(&common->group.group.cg_subsys->su_mutex);
common->state = FSG_STATE_IDLE;
}
spin_unlock_irq(&common->lock);
@@ -2582,17 +2485,25 @@ static int fsg_main_thread(void *common_)
if (!common->ops || !common->ops->thread_exits
|| common->ops->thread_exits(common) < 0) {
- struct fsg_lun *curlun = common->luns;
- unsigned i = common->nluns;
+ struct list_head *cursor;
down_write(&common->filesem);
- for (; i--; ++curlun) {
+
+ mutex_lock(&common->group.group.cg_subsys->su_mutex);
+ list_for_each_prev(cursor, &common->group.group.cg_children) {
+ struct config_item *item;
+ struct fsg_lun *curlun;
+
+ item = list_entry(cursor, struct config_item, ci_entry);
+
+ curlun = to_fsg_lun(item);
if (!fsg_lun_is_open(curlun))
continue;
fsg_lun_close(curlun);
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
}
+ mutex_unlock(&common->group.group.cg_subsys->su_mutex);
up_write(&common->filesem);
}
@@ -2600,156 +2511,241 @@ static int fsg_main_thread(void *common_)
complete_and_exit(&common->thread_notifier, 0);
}
+/****************************** FSG COMMON ******************************/
-/*************************** DEVICE ATTRIBUTES ***************************/
+static void fsg_common_release(struct kref *ref);
-static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
-static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
-static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+void fsg_common_get(struct fsg_common *common)
+{
+ kref_get(&common->ref);
+}
+EXPORT_SYMBOL(fsg_common_get);
-static struct device_attribute dev_attr_ro_cdrom =
- __ATTR(ro, 0444, fsg_show_ro, NULL);
-static struct device_attribute dev_attr_file_nonremovable =
- __ATTR(file, 0444, fsg_show_file, NULL);
+void fsg_common_put(struct fsg_common *common)
+{
+ kref_put(&common->ref, fsg_common_release);
+}
+EXPORT_SYMBOL(fsg_common_put);
+static struct fsg_lun *alloc_fsg_lun(struct config_group *group,
+ const char *name)
+{
+ struct fsg_common *common;
+ struct ufg_function_grp *ufg_function_grp;
+ struct fsg_lun *lun;
+ struct config_item *item;
+ unsigned int tmp;
+ unsigned int leading_zeros;
+ int len;
+ const char *p;
+
+ ufg_function_grp = group ?
+ container_of(group, struct ufg_function_grp, group) : NULL;
+ if (!ufg_function_grp)
+ return ERR_PTR(-ENOMEM);
+ common = ufg_function_grp ?
+ container_of(ufg_function_grp, struct fsg_common, group) : NULL;
-/****************************** FSG COMMON ******************************/
+ if (strncmp(name, "lun", 3))
+ return ERR_PTR(-EINVAL);
+ p = name + 3;
+ if (sscanf(p, "%d%n", &tmp, &len) < 1)
+ return ERR_PTR(-EINVAL);
+ leading_zeros = 0;
+ while (*p++ == '0')
+ leading_zeros++;
+ if (!tmp)
+ leading_zeros--;
+ if (leading_zeros > 0)
+ return ERR_PTR(-EINVAL);
+ if (strlen(name) != len + 3)
+ return ERR_PTR(-EINVAL);
-static void fsg_common_release(struct kref *ref);
+ list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+ lun = to_fsg_lun(item);
+ if (tmp == lun->n_lun)
+ return ERR_PTR(-EBUSY);
+ }
-static void fsg_lun_release(struct device *dev)
+ lun = kzalloc(sizeof(*lun), GFP_KERNEL);
+ if (!lun)
+ return ERR_PTR(-ENOMEM);
+ lun->filesem = &common->filesem;
+ lun->n_lun = tmp;
+
+ config_item_init_type_name(&lun->item.cg_item, name,
+ &fsg_lun_item_type);
+
+ LINFO(lun, "LUN: %s%s%sfile: %s\n",
+ lun->removable ? "removable " : "",
+ lun->ro ? "read only " : "",
+ lun->cdrom ? "CD-ROM " : "",
+ "(no medium)");
+
+ return lun;
+}
+
+static ssize_t fsg_common_show_luns(struct fsg_common *common, char *buf)
{
- /* Nothing needs to be done */
+ return sprintf(buf, "%d\n", common->nluns);
}
-static inline void fsg_common_get(struct fsg_common *common)
+static ssize_t fsg_common_store_luns(struct fsg_common *common, const char
*buf,
+ size_t count)
{
- kref_get(&common->ref);
+ struct config_item *function, *config, *gadget;
+ struct fsg_lun *new;
+ char n[LUN_NAME_MAX];
+ u16 tmp;
+ char *p = (char *)buf;
+ int rc;
+
+ function = common->group.group.cg_item.ci_parent;
+ if (!function)
+ return -EBUSY;
+
+ config = function->ci_parent;
+ if (!config)
+ return -EBUSY;
+
+ gadget = config->ci_parent;
+ if (!gadget)
+ return -EBUSY;
+
+ rc = kstrtou16(p, 10, &tmp);
+ if (rc < 0)
+ return rc;
+ if (tmp > FSG_MAX_LUNS)
+ return -ERANGE;
+
+ common->nluns = tmp;
+ for (tmp = 0; tmp < common->nluns; tmp++) {
+
+ sprintf(n, "lun%d", tmp);
+ new = alloc_fsg_lun(&common->group.group, n);
+ if (IS_ERR(new))
+ goto rollback;
+
+ rc = configfs_create_group(&common->group.group, &new->item);
+ if (rc) {
+ kfree(new);
+
+ goto rollback;
+ }
+
+ }
+
+ return count;
+
+rollback:
+ while (tmp--) {
+ struct config_item *child;
+
+ sprintf(n, "lun%d", tmp);
+ child = config_group_find_item(&common->group.group, n);
+ if (child)
+ configfs_remove_group(to_config_group(child));
+ }
+ return rc;
}
-static inline void fsg_common_put(struct fsg_common *common)
+static ssize_t fsg_common_show_stall(struct fsg_common *common, char *buf)
{
- kref_put(&common->ref, fsg_common_release);
+ return sprintf(buf, "%d\n", common->can_stall);
}
-static struct fsg_common *fsg_common_init(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- struct fsg_config *cfg)
+static ssize_t fsg_common_store_stall(struct fsg_common *common,
+ const char *buf, size_t count)
+{
+ if (count > 2)
+ return -EINVAL;
+
+ if (buf[0] != '0' && buf[0] != '1')
+ return -EINVAL;
+
+ if (count > 1 && buf[1] != '\0')
+ return -EINVAL;
+
+ common->can_stall = buf[0] == '1';
+
+ return count;
+}
+
+CONFIGFS_ATTR_STRUCT(fsg_common);
+
+#define FSG_CONFIG_ATTR_RW(_name) \
+static struct fsg_common_attribute fsg_common_##_name =
\
+ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, fsg_common_show_##_name,\
+ fsg_common_store_##_name)
+
+#define FSG_CONFIG_ATTR_RO(_name) \
+static struct fsg_common_attribute fsg_common_##_name =
\
+ __CONFIGFS_ATTR(_name, S_IRUGO , fsg_common_show_##_name, NULL)
+
+FSG_CONFIG_ATTR_RW(luns);
+FSG_CONFIG_ATTR_RW(stall);
+
+static struct configfs_attribute *fsg_common_attrs[] = {
+ &fsg_common_luns.attr,
+ &fsg_common_stall.attr,
+ NULL,
+};
+
+static struct fsg_common *to_fsg_common(struct config_item *item)
+{
+ struct ufg_function_grp *ufg_function_grp;
+
+ ufg_function_grp =
+ item ? container_of(to_config_group(item),
+ struct ufg_function_grp, group) : NULL;
+ return ufg_function_grp ? container_of(ufg_function_grp,
+ struct fsg_common, group) : NULL;
+}
+
+CONFIGFS_ATTR_OPS(fsg_common);
+
+static void fsg_common_release_item(struct config_item *item)
+{
+ kfree(to_fsg_common(item));
+}
+
+static struct configfs_item_operations fsg_common_item_ops = {
+ .show_attribute = fsg_common_attr_show,
+ .store_attribute = fsg_common_attr_store,
+ .release = fsg_common_release_item,
+};
+
+static struct config_item_type fsg_common_item_type = {
+ .ct_attrs = fsg_common_attrs,
+ .ct_item_ops = &fsg_common_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+struct fsg_common *fsg_common_init(struct fsg_common *common)
{
- struct usb_gadget *gadget = cdev->gadget;
struct fsg_buffhd *bh;
- struct fsg_lun *curlun;
- struct fsg_lun_config *lcfg;
- int nluns, i, rc;
- char *pathbuf;
+ int i, rc;
rc = fsg_num_buffers_validate();
if (rc != 0)
return ERR_PTR(rc);
- /* Find out how many LUNs there should be */
- nluns = cfg->nluns;
- if (nluns < 1 || nluns > FSG_MAX_LUNS) {
- dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
+ /* TODO: move it somewhere else */
+ /*if (common->nluns < 1 || common->nluns > FSG_MAX_LUNS) {
+ printk("invalid number of LUNs: %u\n", nluns);
return ERR_PTR(-EINVAL);
- }
-
- /* Allocate? */
- if (!common) {
- common = kzalloc(sizeof *common, GFP_KERNEL);
- if (!common)
- return ERR_PTR(-ENOMEM);
- common->free_storage_on_release = 1;
- } else {
- memset(common, 0, sizeof *common);
- common->free_storage_on_release = 0;
- }
+ }*/
common->buffhds = kcalloc(fsg_num_buffers,
sizeof *(common->buffhds), GFP_KERNEL);
- if (!common->buffhds) {
- if (common->free_storage_on_release)
- kfree(common);
+ if (!common->buffhds)
return ERR_PTR(-ENOMEM);
- }
-
- common->ops = cfg->ops;
- common->private_data = cfg->private_data;
- common->gadget = gadget;
- common->ep0 = gadget->ep0;
- common->ep0req = cdev->req;
- common->cdev = cdev;
-
- /* Maybe allocate device-global string IDs, and patch descriptors */
- if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
- rc = usb_string_id(cdev);
- if (unlikely(rc < 0))
- goto error_release;
- fsg_strings[FSG_STRING_INTERFACE].id = rc;
- fsg_intf_desc.iInterface = rc;
- }
-
- /*
- * Create the LUNs, open their backing files, and register the
- * LUN devices in sysfs.
- */
- curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
- if (unlikely(!curlun)) {
- rc = -ENOMEM;
- goto error_release;
- }
- common->luns = curlun;
+ common->ops = NULL;
+ common->private_data = NULL;
init_rwsem(&common->filesem);
- for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
- 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);
-
- 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);
- 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;
- }
- }
- common->nluns = nluns;
-
/* Data buffers cyclic list */
bh = common->buffhds;
i = fsg_num_buffers;
@@ -2766,24 +2762,6 @@ buffhds_first_it:
} while (--i);
bh->next = common->buffhds;
- /* Prepare inquiryString */
- i = get_default_bcdDevice();
- snprintf(common->inquiry_string, sizeof common->inquiry_string,
- "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
- /* Assume product name dependent on the first LUN */
- cfg->product_name ?: (common->luns->cdrom
- ? "File-Stor Gadget"
- : "File-CD Gadget"),
- i);
-
- /*
- * 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 = cfg->can_stall &&
- !(gadget_is_at91(common->gadget));
-
spin_lock_init(&common->lock);
kref_init(&common->ref);
@@ -2798,49 +2776,100 @@ buffhds_first_it:
init_waitqueue_head(&common->fsg_wait);
/* Information */
- 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 = common->luns;
- i < nluns;
- ++curlun, ++i) {
- 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);
+ pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
+ pr_info("Number of LUNs=%d\n", common->nluns);
- DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
+ pr_info("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. */
fsg_common_release(&common->ref);
return ERR_PTR(rc);
}
+EXPORT_SYMBOL(fsg_common_init);
+
+static struct fsg_common *fsg_common_init_cdev(struct fsg_common *common,
+ struct usb_composite_dev *cdev)
+{
+ struct usb_gadget *gadget = cdev->gadget;
+ int rc, i;
+
+ common->gadget = gadget;
+ common->ep0 = gadget->ep0;
+ common->ep0req = cdev->req;
+ common->cdev = cdev;
+
+ /* Maybe allocate device-global string IDs, and patch descriptors */
+ if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
+ rc = usb_string_id(cdev);
+ if (unlikely(rc < 0))
+ goto error_release;
+ fsg_strings[FSG_STRING_INTERFACE].id = rc;
+ fsg_intf_desc.iInterface = rc;
+ }
+
+ /* Prepare inquiryString */
+ i = get_default_bcdDevice();
+ snprintf(common->inquiry_string, sizeof(common->inquiry_string),
+ "%-8s%-16s%04x", "Linux",
+ /* Assume product name dependent on the first LUN */
+ /* TODO: actually check first child's "cdrom" flag */
+ "USB mass storage", i);
+
+ /*
+ * 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 = common->can_stall &&
+ !(gadget_is_at91(common->gadget));
+
+ return common;
+
+error_release:
+ common->state = FSG_STATE_TERMINATED; /* The thread is dead */
+ /* Call fsg_common_release() directly, ref might be not initialised. */
+ fsg_common_release(&common->ref);
+ return ERR_PTR(rc);
+}
+
+struct config_group *alloc_fsg_common(struct config_group *group,
+ const char *n)
+{
+ struct config_item *item;
+ struct fsg_common *common, *ret;
+
+ list_for_each_entry(item, &group->cg_children, ci_entry)
+ if (!strcmp(n, item->ci_name))
+ return ERR_PTR(-EBUSY);
+
+ common = kzalloc(sizeof(*common), GFP_KERNEL);
+ if (!common)
+ return ERR_PTR(-ENOMEM);
+
+ ret = fsg_common_init(common);
+ if (IS_ERR(ret)) {
+ kfree(common);
+ return (struct config_group *)ret;
+ }
+ common->group.type = UFG_FUNCTION;
+
+ config_group_init_type_name(&common->group.group, n,
+ &fsg_common_item_type);
+
+ return &common->group.group;
+}
+EXPORT_SYMBOL(alloc_fsg_common);
static void fsg_common_release(struct kref *ref)
{
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+ struct config_item *item;
/* If the thread isn't already dead, tell it to exit now */
if (common->state != FSG_STATE_TERMINATED) {
@@ -2848,28 +2877,10 @@ static void fsg_common_release(struct kref *ref)
wait_for_completion(&common->thread_notifier);
}
- if (likely(common->luns)) {
- struct fsg_lun *lun = common->luns;
- unsigned i = common->nluns;
-
- /* In error recovery common->nluns may be zero. */
- for (; i; --i, ++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);
- fsg_lun_close(lun);
- device_unregister(&lun->dev);
- }
-
- kfree(common->luns);
+ list_for_each_entry(item, &common->group.group.cg_children, ci_entry) {
+ struct fsg_lun *lun = to_fsg_lun(item);
+ fsg_lun_close(lun);
}
-
{
struct fsg_buffhd *bh = common->buffhds;
unsigned i = fsg_num_buffers;
@@ -2879,11 +2890,8 @@ static void fsg_common_release(struct kref *ref)
}
kfree(common->buffhds);
- if (common->free_storage_on_release)
- kfree(common);
}
-
/*-------------------------------------------------------------------------*/
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
@@ -2899,9 +2907,14 @@ static void fsg_unbind(struct usb_configuration *c,
struct usb_function *f)
wait_event(common->fsg_wait, common->fsg != fsg);
}
+ usb_free_all_descriptors(f);
fsg_common_put(common);
- usb_free_all_descriptors(&fsg->function);
- kfree(fsg);
+ usb_put_function(f);
+}
+
+static void fsg_free(struct usb_function *f)
+{
+ kfree(fsg_from_func(f));
}
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
@@ -2965,22 +2978,61 @@ autoconf_fail:
}
/****************************** ADD FUNCTION ******************************/
+static void msg_cleanup(void)
+{
+ clear_bit(0, &msg_registered);
+}
+
+static int msg_thread_exits(struct fsg_common *common)
+{
+ msg_cleanup();
+ return 0;
+}
+
+static int fsg_add_function(struct usb_configuration *c, struct usb_function
*f,
+ struct config_item *item, void *data)
+{
+ static const struct fsg_operations ops = {
+ .thread_exits = msg_thread_exits,
+ };
+
+ struct fsg_common *common = to_fsg_common(item);
+ struct fsg_dev *fsg;
+ struct usb_composite_dev *cdev = data;
+ int status;
+
+ common->ops = &ops;
+ fsg_common_init_cdev(common, cdev);
+
+ fsg = container_of(f, struct fsg_dev, function);
+ fsg->common = common;
+
+ status = usb_add_function(c, f);
+ if (status) {
+ usb_put_function(f);
+ fsg_common_put(common);
+ return status;
+ }
+ fsg_common_get(common);
+ set_bit(0, &msg_registered);
+
+ return status;
+}
+
+/****************************** ALLOCATE FUNCTION *************************/
static struct usb_gadget_strings *fsg_strings_array[] = {
&fsg_stringtab,
NULL,
};
-static int fsg_bind_config(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct fsg_common *common)
+static struct usb_function *fsg_alloc(void)
{
struct fsg_dev *fsg;
- int rc;
- fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+ fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
if (unlikely(!fsg))
- return -ENOMEM;
+ return NULL;
fsg->function.name = FSG_DRIVER_DESC;
fsg->function.strings = fsg_strings_array;
@@ -2989,8 +3041,10 @@ static int fsg_bind_config(struct usb_composite_dev
*cdev,
fsg->function.setup = fsg_setup;
fsg->function.set_alt = fsg_set_alt;
fsg->function.disable = fsg_disable;
+ fsg->function.free_func = fsg_free;
+ fsg->function.make_group = alloc_fsg_common;
+ fsg->function.add_function = fsg_add_function;
- fsg->common = common;
/*
* Our caller holds a reference to common structure so we
* don't have to be worry about it being freed until we return
@@ -2999,100 +3053,9 @@ static int fsg_bind_config(struct usb_composite_dev
*cdev,
* call to usb_add_function() was successful.
*/
- rc = usb_add_function(c, &fsg->function);
- if (unlikely(rc))
- kfree(fsg);
- else
- fsg_common_get(fsg->common);
- return rc;
+ return &fsg->function;
}
-
-/************************* Module parameters *************************/
-
-struct fsg_module_parameters {
- char *file[FSG_MAX_LUNS];
- bool ro[FSG_MAX_LUNS];
- bool removable[FSG_MAX_LUNS];
- bool cdrom[FSG_MAX_LUNS];
- bool nofua[FSG_MAX_LUNS];
-
- unsigned int file_count, ro_count, removable_count, cdrom_count;
- unsigned int nofua_count;
- unsigned int luns; /* nluns */
- bool stall; /* can_stall */
-};
-
-#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
- module_param_array_named(prefix ## name, params.name, type, \
- &prefix ## params.name ## _count, \
- S_IRUGO); \
- MODULE_PARM_DESC(prefix ## name, desc)
-
-#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
- module_param_named(prefix ## name, params.name, type, \
- S_IRUGO); \
- MODULE_PARM_DESC(prefix ## name, desc)
-
-#define FSG_MODULE_PARAMETERS(prefix, params) \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \
- "names of backing files or devices"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \
- "true to force read-only"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \
- "true to simulate removable media"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
- "true to simulate CD-ROM instead of disk"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \
- "true to ignore SCSI WRITE(10,12) FUA bit"); \
- _FSG_MODULE_PARAM(prefix, params, luns, uint, \
- "number of LUNs"); \
- _FSG_MODULE_PARAM(prefix, params, stall, bool, \
- "false to prevent bulk stalls")
-
-static void
-fsg_config_from_params(struct fsg_config *cfg,
- const struct fsg_module_parameters *params)
-{
- struct fsg_lun_config *lun;
- unsigned i;
-
- /* Configure LUNs */
- cfg->nluns =
- min(params->luns ?: (params->file_count ?: 1u),
- (unsigned)FSG_MAX_LUNS);
- for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
- lun->ro = !!params->ro[i];
- lun->cdrom = !!params->cdrom[i];
- lun->removable = !!params->removable[i];
- lun->filename =
- params->file_count > i && params->file[i][0]
- ? params->file[i]
- : 0;
- }
-
- /* Let MSF use defaults */
- cfg->vendor_name = 0;
- cfg->product_name = 0;
-
- cfg->ops = NULL;
- cfg->private_data = NULL;
-
- /* Finalise */
- cfg->can_stall = params->stall;
-}
-
-static inline struct fsg_common *
-fsg_common_from_params(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- const struct fsg_module_parameters *params)
- __attribute__((unused));
-static inline struct fsg_common *
-fsg_common_from_params(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- const struct fsg_module_parameters *params)
-{
- struct fsg_config cfg;
- fsg_config_from_params(&cfg, params);
- return fsg_common_init(common, cdev, &cfg);
-}
+DECLARE_USB_FUNCTION(MassStorage, fsg_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Nazarewicz");
diff --git a/drivers/usb/gadget/f_mass_storage.h
b/drivers/usb/gadget/f_mass_storage.h
new file mode 100644
index 0000000..fa583db
--- /dev/null
+++ b/drivers/usb/gadget/f_mass_storage.h
@@ -0,0 +1,99 @@
+#ifndef F_MASS_STORAGE_H
+#define F_MASS_STORAGE_H
+
+#include "storage_common.h"
+#include "usb_functions.h"
+
+#define LUN_NAME_MAX 16
+
+struct fsg_common;
+struct fsg_operations;
+struct usb_composite_dev;
+struct fsg_dev;
+struct fsg_lun;
+
+/* FSF callback functions */
+struct fsg_operations {
+ /*
+ * Callback function to call when thread exits. If no
+ * callback is set or it returns value lower then zero MSF
+ * will force eject all LUNs it operates on (including those
+ * marked as non-removable or with prevent_medium_removal flag
+ * set).
+ */
+ int (*thread_exits)(struct fsg_common *common);
+};
+
+/* Data shared by all the FSG instances. */
+struct fsg_common {
+ struct ufg_function_grp group;
+ enum ufg_hdr_type type;
+
+ struct usb_gadget *gadget;
+ struct usb_composite_dev *cdev;
+ struct fsg_dev *fsg, *new_fsg;
+ wait_queue_head_t fsg_wait;
+
+ /* filesem protects: backing files in use */
+ struct rw_semaphore filesem;
+
+ /* lock protects: state, all the req_busy's */
+ spinlock_t lock;
+
+ struct usb_ep *ep0; /* Copy of gadget->ep0 */
+ struct usb_request *ep0req; /* Copy of cdev->req */
+ unsigned int ep0_req_tag;
+
+ struct fsg_buffhd *next_buffhd_to_fill;
+ struct fsg_buffhd *next_buffhd_to_drain;
+ struct fsg_buffhd *buffhds;
+
+ int cmnd_size;
+ u8 cmnd[MAX_COMMAND_SIZE];
+
+ unsigned int nluns;
+ unsigned int lun;
+ struct fsg_lun *curlun;
+
+ unsigned int bulk_out_maxpacket;
+ enum fsg_state state; /* For exception handling */
+ unsigned int exception_req_tag;
+
+ enum data_direction data_dir;
+ u32 data_size;
+ u32 data_size_from_cmnd;
+ u32 tag;
+ u32 residue;
+ u32 usb_amount_left;
+
+ unsigned int can_stall:1;
+ unsigned int free_storage_on_release:1;
+ unsigned int phase_error:1;
+ unsigned int short_packet_received:1;
+ unsigned int bad_lun_okay:1;
+ unsigned int running:1;
+
+ int thread_wakeup_needed;
+ struct completion thread_notifier;
+ struct task_struct *thread_task;
+
+ /* Callback functions. */
+ const struct fsg_operations *ops;
+ /* Gadget's private data. */
+ void *private_data;
+
+ /*
+ * Vendor (8 chars), product (16 chars), release (4
+ * hexadecimal digits) and NUL byte
+ */
+ char inquiry_string[8 + 16 + 4 + 1];
+
+ struct kref ref;
+};
+
+struct fsg_common *fsg_common_init(struct fsg_common *common);
+
+void fsg_common_get(struct fsg_common *common);
+void fsg_common_put(struct fsg_common *common);
+
+#endif
diff --git a/drivers/usb/gadget/storage_common.c
b/drivers/usb/gadget/storage_common.c
index 0e3ae43..9e6136c 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -25,19 +25,12 @@
#include <linux/usb/storage.h>
+#include <linux/configfs.h>
#include <scsi/scsi.h>
#include <asm/unaligned.h>
+#include "storage_common.h"
-/*
- * Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with any other driver!! Ever!!
- * Instead: allocate your own, using normal USB-IF procedures.
- */
-#define FSG_VENDOR_ID 0x0525 /* NetChip */
-#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
-
/*-------------------------------------------------------------------------*/
@@ -53,10 +46,9 @@
#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 LERROR(lun, fmt, args...) pr_err(fmt, ## args)
+#define LDBG(lun, fmt, args...) pr_debug(fmt, ## args)
+#define LINFO(lun, fmt, args...) pr_info(fmt, ## args)
#ifdef DUMP_MSGS
@@ -105,9 +97,6 @@ struct interrupt_data {
#define USB_CBI_ADSC_REQUEST 0x00
-/* Length of a SCSI Command Data Block */
-#define MAX_COMMAND_SIZE 16
-
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
#define SS_NO_SENSE 0
#define SS_COMMUNICATION_FAILURE 0x040800
@@ -152,7 +141,11 @@ struct fsg_lun {
unsigned int blkbits; /* Bits of logical block size of bound
block device */
unsigned int blksize; /* logical block size of bound block
device */
- struct device dev;
+
+ /* configfs-related section */
+ struct config_group item;
+ struct rw_semaphore *filesem;
+ unsigned int n_lun;
};
static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
@@ -160,11 +153,63 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
return curlun->filp != NULL;
}
-static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev)
+CONFIGFS_ATTR_STRUCT(fsg_lun);
+
+#define FSG_LUN_ATTR_RW(_name) \
+static struct fsg_lun_attribute fsg_lun_##_name = \
+ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, fsg_lun_show_##_name, \
+ fsg_lun_store_##_name)
+
+static ssize_t fsg_lun_show_ro(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_show_nofua(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_show_file(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_store_ro(struct fsg_lun *curlun, const char *buf,
+ size_t count);
+static ssize_t fsg_lun_store_nofua(struct fsg_lun *curlun, const char *buf,
+ size_t count);
+static ssize_t fsg_lun_store_file(struct fsg_lun *curlun, const char *buf,
+ size_t count);
+static ssize_t fsg_lun_show_removable(struct fsg_lun *curlun, char *buf);
+static ssize_t fsg_lun_store_removable(struct fsg_lun *curlun, const char *buf,
+ size_t count);
+
+FSG_LUN_ATTR_RW(ro);
+FSG_LUN_ATTR_RW(nofua);
+FSG_LUN_ATTR_RW(file);
+FSG_LUN_ATTR_RW(removable);
+
+static struct configfs_attribute *fsg_lun_attrs[] = {
+ &fsg_lun_ro.attr,
+ &fsg_lun_nofua.attr,
+ &fsg_lun_file.attr,
+ &fsg_lun_removable.attr,
+ NULL,
+};
+
+static struct fsg_lun *to_fsg_lun(struct config_item *item)
+{
+ return item ? container_of(to_config_group(item), struct fsg_lun, item)
+ : NULL;
+}
+
+CONFIGFS_ATTR_OPS(fsg_lun);
+
+static void fsg_lun_item_release(struct config_item *item)
{
- return container_of(dev, struct fsg_lun, dev);
+ kfree(to_fsg_lun(item));
}
+static struct configfs_item_operations fsg_lun_ops = {
+ .show_attribute = fsg_lun_attr_show,
+ .store_attribute = fsg_lun_attr_store,
+ .release = fsg_lun_item_release,
+};
+
+static struct config_item_type fsg_lun_item_type = {
+ .ct_attrs = fsg_lun_attrs,
+ .ct_item_ops = &fsg_lun_ops,
+ .ct_owner = THIS_MODULE,
+};
/* Big enough to hold our biggest descriptor */
#define EP0_BUFSIZE 256
@@ -199,9 +244,6 @@ static inline int fsg_num_buffers_validate(void)
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)
-/* Maximal number of LUNs supported in mass storage function */
-#define FSG_MAX_LUNS 8
-
enum fsg_buffer_state {
BUF_STATE_EMPTY = 0,
BUF_STATE_FULL,
@@ -226,29 +268,6 @@ struct fsg_buffhd {
int outreq_busy;
};
-enum fsg_state {
- /* This one isn't used anywhere */
- FSG_STATE_COMMAND_PHASE = -10,
- FSG_STATE_DATA_PHASE,
- FSG_STATE_STATUS_PHASE,
-
- FSG_STATE_IDLE = 0,
- FSG_STATE_ABORT_BULK_OUT,
- FSG_STATE_RESET,
- FSG_STATE_INTERFACE_CHANGE,
- FSG_STATE_CONFIG_CHANGE,
- FSG_STATE_DISCONNECT,
- FSG_STATE_EXIT,
- FSG_STATE_TERMINATED
-};
-
-enum data_direction {
- DATA_DIR_UNKNOWN = 0,
- DATA_DIR_FROM_HOST,
- DATA_DIR_TO_HOST,
- DATA_DIR_NONE
-};
-
/*-------------------------------------------------------------------------*/
@@ -468,6 +487,8 @@ static void fsg_lun_close(struct fsg_lun *curlun)
LDBG(curlun, "close backing file\n");
fput(curlun->filp);
curlun->filp = NULL;
+ configfs_undepend_item(curlun->item.cg_subsys,
+ &curlun->item.cg_item);
}
}
@@ -484,6 +505,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char
*filename)
unsigned int blkbits;
unsigned int blksize;
+ configfs_depend_item(curlun->item.cg_subsys, &curlun->item.cg_item);
+
/* R/W if we can, R/O if we must */
ro = curlun->initially_ro;
if (!ro) {
@@ -567,6 +590,9 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char
*filename)
out:
fput(filp);
+ if (rc)
+ configfs_undepend_item(curlun->item.cg_subsys,
+ &curlun->item.cg_item);
return rc;
}
@@ -608,29 +634,21 @@ static void store_cdrom_address(u8 *dest, int msf, u32
addr)
/*-------------------------------------------------------------------------*/
-static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fsg_lun_show_ro(struct fsg_lun *curlun, char *buf)
{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
-
return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
? curlun->ro
: curlun->initially_ro);
}
-static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute
*attr,
- char *buf)
+static ssize_t fsg_lun_show_nofua(struct fsg_lun *curlun, char *buf)
{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
-
return sprintf(buf, "%u\n", curlun->nofua);
}
-static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fsg_lun_show_file(struct fsg_lun *curlun, char *buf)
{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
+ struct rw_semaphore *filesem = curlun->filesem;
char *p;
ssize_t rc;
@@ -653,13 +671,11 @@ static ssize_t fsg_show_file(struct device *dev, struct
device_attribute *attr,
return rc;
}
-
-static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fsg_lun_store_ro(struct fsg_lun *curlun, const char *buf,
+ size_t count)
{
ssize_t rc;
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
+ struct rw_semaphore *filesem = curlun->filesem;
unsigned ro;
rc = kstrtouint(buf, 2, &ro);
@@ -684,11 +700,9 @@ static ssize_t fsg_store_ro(struct device *dev, struct
device_attribute *attr,
return rc;
}
-static ssize_t fsg_store_nofua(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fsg_lun_store_nofua(struct fsg_lun *curlun, const char *buf,
+ size_t count)
{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
unsigned nofua;
int ret;
@@ -705,11 +719,10 @@ static ssize_t fsg_store_nofua(struct device *dev,
return count;
}
-static ssize_t fsg_store_file(struct device *dev, struct device_attribute
*attr,
- const char *buf, size_t count)
+static ssize_t fsg_lun_store_file(struct fsg_lun *curlun, const char *buf,
+ size_t count)
{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
+ struct rw_semaphore *filesem = curlun->filesem;
int rc = 0;
if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
@@ -736,3 +749,25 @@ static ssize_t fsg_store_file(struct device *dev, struct
device_attribute *attr,
up_write(filesem);
return (rc < 0 ? rc : count);
}
+
+static ssize_t fsg_lun_show_removable(struct fsg_lun *curlun, char *buf)
+{
+ return sprintf(buf, "%d\n", curlun->removable);
+}
+
+static ssize_t fsg_lun_store_removable(struct fsg_lun *curlun, const char *buf,
+ size_t count)
+{
+ if (fsg_lun_is_open(curlun)) {
+ LDBG(curlun, "media type change prevented\n");
+ return -EBUSY;
+ }
+
+ if (buf[0] != '0' && buf[0] != '1')
+ return -EINVAL;
+
+ curlun->removable = buf[0] == '1';
+
+ return count;
+}
+
diff --git a/drivers/usb/gadget/storage_common.h
b/drivers/usb/gadget/storage_common.h
new file mode 100644
index 0000000..52528f2
--- /dev/null
+++ b/drivers/usb/gadget/storage_common.h
@@ -0,0 +1,43 @@
+#ifndef STORAGE_COMMON_H
+#define STORAGE_COMMON_H
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID 0x0525 /* NetChip */
+#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
+
+/* Maximal number of LUNs supported in mass storage function */
+#define FSG_MAX_LUNS 8
+
+/* Length of a SCSI Command Data Block */
+#define MAX_COMMAND_SIZE 16
+
+enum fsg_state {
+ /* This one isn't used anywhere */
+ FSG_STATE_COMMAND_PHASE = -10,
+ FSG_STATE_DATA_PHASE,
+ FSG_STATE_STATUS_PHASE,
+
+ FSG_STATE_IDLE = 0,
+ FSG_STATE_ABORT_BULK_OUT,
+ FSG_STATE_RESET,
+ FSG_STATE_INTERFACE_CHANGE,
+ FSG_STATE_CONFIG_CHANGE,
+ FSG_STATE_DISCONNECT,
+ FSG_STATE_EXIT,
+ FSG_STATE_TERMINATED
+};
+
+enum data_direction {
+ DATA_DIR_UNKNOWN = 0,
+ DATA_DIR_FROM_HOST,
+ DATA_DIR_TO_HOST,
+ DATA_DIR_NONE
+};
+
+
+#endif
--
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html