|
@@ -279,9 +279,8 @@ struct fsg_common {
|
|
|
int cmnd_size;
|
|
|
u8 cmnd[MAX_COMMAND_SIZE];
|
|
|
|
|
|
- unsigned int nluns;
|
|
|
unsigned int lun;
|
|
|
- struct fsg_lun **luns;
|
|
|
+ struct fsg_lun *luns[FSG_MAX_LUNS];
|
|
|
struct fsg_lun *curlun;
|
|
|
|
|
|
unsigned int bulk_out_maxpacket;
|
|
@@ -490,6 +489,16 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
|
|
|
spin_unlock(&common->lock);
|
|
|
}
|
|
|
|
|
|
+static int _fsg_common_get_max_lun(struct fsg_common *common)
|
|
|
+{
|
|
|
+ int i = ARRAY_SIZE(common->luns) - 1;
|
|
|
+
|
|
|
+ while (i >= 0 && !common->luns[i])
|
|
|
+ --i;
|
|
|
+
|
|
|
+ return i;
|
|
|
+}
|
|
|
+
|
|
|
static int fsg_setup(struct usb_function *f,
|
|
|
const struct usb_ctrlrequest *ctrl)
|
|
|
{
|
|
@@ -533,7 +542,7 @@ static int fsg_setup(struct usb_function *f,
|
|
|
w_length != 1)
|
|
|
return -EDOM;
|
|
|
VDBG(fsg, "get max LUN\n");
|
|
|
- *(u8 *)req->buf = fsg->common->nluns - 1;
|
|
|
+ *(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common);
|
|
|
|
|
|
/* Respond with data/status */
|
|
|
req->length = min((u16)1, w_length);
|
|
@@ -2131,8 +2140,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
|
}
|
|
|
|
|
|
/* Is the CBW meaningful? */
|
|
|
- if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
|
|
|
- cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
|
|
|
+ if (cbw->Lun >= ARRAY_SIZE(common->luns) ||
|
|
|
+ cbw->Flags & ~US_BULK_FLAG_IN || cbw->Length <= 0 ||
|
|
|
+ cbw->Length > MAX_COMMAND_SIZE) {
|
|
|
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
|
|
|
"cmdlen %u\n",
|
|
|
cbw->Lun, cbw->Flags, cbw->Length);
|
|
@@ -2159,7 +2169,7 @@ 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 < common->nluns)
|
|
|
+ if (common->lun < ARRAY_SIZE(common->luns))
|
|
|
common->curlun = common->luns[common->lun];
|
|
|
else
|
|
|
common->curlun = NULL;
|
|
@@ -2307,7 +2317,7 @@ reset:
|
|
|
}
|
|
|
|
|
|
common->running = 1;
|
|
|
- for (i = 0; i < common->nluns; ++i)
|
|
|
+ for (i = 0; i < ARRAY_SIZE(common->luns); ++i)
|
|
|
if (common->luns[i])
|
|
|
common->luns[i]->unit_attention_data =
|
|
|
SS_RESET_OCCURRED;
|
|
@@ -2409,7 +2419,7 @@ 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) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
|
|
curlun = common->luns[i];
|
|
|
if (!curlun)
|
|
|
continue;
|
|
@@ -2453,7 +2463,7 @@ static void handle_exception(struct fsg_common *common)
|
|
|
* a waste of time. Ditto for the INTERFACE_CHANGE and
|
|
|
* CONFIG_CHANGE cases.
|
|
|
*/
|
|
|
- /* for (i = 0; i < common->nluns; ++i) */
|
|
|
+ /* for (i = 0; i < common->ARRAY_SIZE(common->luns); ++i) */
|
|
|
/* if (common->luns[i]) */
|
|
|
/* common->luns[i]->unit_attention_data = */
|
|
|
/* SS_RESET_OCCURRED; */
|
|
@@ -2552,12 +2562,11 @@ static int fsg_main_thread(void *common_)
|
|
|
|
|
|
if (!common->ops || !common->ops->thread_exits
|
|
|
|| common->ops->thread_exits(common) < 0) {
|
|
|
- struct fsg_lun **curlun_it = common->luns;
|
|
|
- unsigned i = common->nluns;
|
|
|
+ int i;
|
|
|
|
|
|
down_write(&common->filesem);
|
|
|
- for (; i--; ++curlun_it) {
|
|
|
- struct fsg_lun *curlun = *curlun_it;
|
|
|
+ for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
|
|
|
+ struct fsg_lun *curlun = common->luns[i];
|
|
|
if (!curlun || !fsg_lun_is_open(curlun))
|
|
|
continue;
|
|
|
|
|
@@ -2676,6 +2685,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
|
|
|
init_completion(&common->thread_notifier);
|
|
|
init_waitqueue_head(&common->fsg_wait);
|
|
|
common->state = FSG_STATE_TERMINATED;
|
|
|
+ memset(common->luns, 0, sizeof(common->luns));
|
|
|
|
|
|
return common;
|
|
|
}
|
|
@@ -2764,42 +2774,10 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n)
|
|
|
|
|
|
void fsg_common_remove_luns(struct fsg_common *common)
|
|
|
{
|
|
|
- _fsg_common_remove_luns(common, common->nluns);
|
|
|
+ _fsg_common_remove_luns(common, ARRAY_SIZE(common->luns));
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
|
|
|
|
|
|
-void fsg_common_free_luns(struct fsg_common *common)
|
|
|
-{
|
|
|
- fsg_common_remove_luns(common);
|
|
|
- kfree(common->luns);
|
|
|
- common->luns = NULL;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(fsg_common_free_luns);
|
|
|
-
|
|
|
-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(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
|
|
|
- if (unlikely(!curlun))
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- if (common->luns)
|
|
|
- fsg_common_free_luns(common);
|
|
|
-
|
|
|
- common->luns = curlun;
|
|
|
- common->nluns = nluns;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(fsg_common_set_nluns);
|
|
|
-
|
|
|
void fsg_common_set_ops(struct fsg_common *common,
|
|
|
const struct fsg_operations *ops)
|
|
|
{
|
|
@@ -2881,7 +2859,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
|
|
|
char *pathbuf, *p;
|
|
|
int rc = -ENOMEM;
|
|
|
|
|
|
- if (!common->nluns || !common->luns)
|
|
|
+ if (id >= ARRAY_SIZE(common->luns))
|
|
|
return -ENODEV;
|
|
|
|
|
|
if (common->luns[id])
|
|
@@ -2965,14 +2943,16 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg)
|
|
|
char buf[8]; /* enough for 100000000 different numbers, decimal */
|
|
|
int i, rc;
|
|
|
|
|
|
- for (i = 0; i < common->nluns; ++i) {
|
|
|
+ fsg_common_remove_luns(common);
|
|
|
+
|
|
|
+ for (i = 0; i < cfg->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);
|
|
|
+ pr_info("Number of LUNs=%d\n", cfg->nluns);
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -3021,6 +3001,7 @@ EXPORT_SYMBOL_GPL(fsg_common_run_thread);
|
|
|
static void fsg_common_release(struct kref *ref)
|
|
|
{
|
|
|
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
|
|
+ int i;
|
|
|
|
|
|
/* If the thread isn't already dead, tell it to exit now */
|
|
|
if (common->state != FSG_STATE_TERMINATED) {
|
|
@@ -3028,22 +3009,14 @@ static void fsg_common_release(struct kref *ref)
|
|
|
wait_for_completion(&common->thread_notifier);
|
|
|
}
|
|
|
|
|
|
- if (likely(common->luns)) {
|
|
|
- struct fsg_lun **lun_it = common->luns;
|
|
|
- unsigned i = common->nluns;
|
|
|
-
|
|
|
- /* In error recovery common->nluns may be zero. */
|
|
|
- for (; i; --i, ++lun_it) {
|
|
|
- struct fsg_lun *lun = *lun_it;
|
|
|
- if (!lun)
|
|
|
- continue;
|
|
|
- fsg_lun_close(lun);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
|
|
+ struct fsg_lun *lun = common->luns[i];
|
|
|
+ if (!lun)
|
|
|
+ continue;
|
|
|
+ fsg_lun_close(lun);
|
|
|
if (device_is_registered(&lun->dev))
|
|
|
- device_unregister(&lun->dev);
|
|
|
- kfree(lun);
|
|
|
- }
|
|
|
-
|
|
|
- kfree(common->luns);
|
|
|
+ device_unregister(&lun->dev);
|
|
|
+ kfree(lun);
|
|
|
}
|
|
|
|
|
|
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
|
|
@@ -3057,6 +3030,7 @@ static void fsg_common_release(struct kref *ref)
|
|
|
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
{
|
|
|
struct fsg_dev *fsg = fsg_from_func(f);
|
|
|
+ struct fsg_common *common = fsg->common;
|
|
|
struct usb_gadget *gadget = c->cdev->gadget;
|
|
|
int i;
|
|
|
struct usb_ep *ep;
|
|
@@ -3064,6 +3038,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
int ret;
|
|
|
struct fsg_opts *opts;
|
|
|
|
|
|
+ /* Don't allow to bind if we don't have at least one LUN */
|
|
|
+ ret = _fsg_common_get_max_lun(common);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_err("There should be at least one LUN.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
opts = fsg_opts_from_func_inst(f->fi);
|
|
|
if (!opts->no_configfs) {
|
|
|
ret = fsg_common_set_cdev(fsg->common, c->cdev,
|
|
@@ -3517,14 +3498,11 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
|
|
rc = PTR_ERR(opts->common);
|
|
|
goto release_opts;
|
|
|
}
|
|
|
- rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS);
|
|
|
- if (rc)
|
|
|
- goto release_opts;
|
|
|
|
|
|
rc = fsg_common_set_num_buffers(opts->common,
|
|
|
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
|
|
|
if (rc)
|
|
|
- goto release_luns;
|
|
|
+ goto release_opts;
|
|
|
|
|
|
pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
|
|
|
|
|
@@ -3547,8 +3525,6 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
|
|
|
|
|
release_buffers:
|
|
|
fsg_common_free_buffers(opts->common);
|
|
|
-release_luns:
|
|
|
- kfree(opts->common->luns);
|
|
|
release_opts:
|
|
|
kfree(opts);
|
|
|
return ERR_PTR(rc);
|
|
@@ -3574,23 +3550,12 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
|
|
|
struct fsg_opts *opts = fsg_opts_from_func_inst(fi);
|
|
|
struct fsg_common *common = opts->common;
|
|
|
struct fsg_dev *fsg;
|
|
|
- unsigned nluns, i;
|
|
|
|
|
|
fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
|
|
|
if (unlikely(!fsg))
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
mutex_lock(&opts->lock);
|
|
|
- if (!opts->refcnt) {
|
|
|
- for (nluns = i = 0; i < FSG_MAX_LUNS; ++i)
|
|
|
- if (common->luns[i])
|
|
|
- nluns = i + 1;
|
|
|
- if (!nluns)
|
|
|
- pr_warn("No LUNS defined, continuing anyway\n");
|
|
|
- else
|
|
|
- common->nluns = nluns;
|
|
|
- pr_info("Number of LUNs=%u\n", common->nluns);
|
|
|
- }
|
|
|
opts->refcnt++;
|
|
|
mutex_unlock(&opts->lock);
|
|
|
|