|
@@ -316,6 +316,27 @@ static const char fsg_string_interface[] = "Mass Storage";
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
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. */
|
|
@@ -368,8 +389,8 @@ struct fsg_common {
|
|
|
struct completion thread_notifier;
|
|
|
struct task_struct *thread_task;
|
|
|
|
|
|
- /* Callback function to call when thread exits. */
|
|
|
- int (*thread_exits)(struct fsg_common *common);
|
|
|
+ /* Callback functions. */
|
|
|
+ const struct fsg_operations *ops;
|
|
|
/* Gadget's private data. */
|
|
|
void *private_data;
|
|
|
|
|
@@ -393,12 +414,8 @@ struct fsg_config {
|
|
|
const char *lun_name_format;
|
|
|
const char *thread_name;
|
|
|
|
|
|
- /* 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);
|
|
|
+ /* Callback functions. */
|
|
|
+ const struct fsg_operations *ops;
|
|
|
/* Gadget's private data. */
|
|
|
void *private_data;
|
|
|
|
|
@@ -434,6 +451,7 @@ static inline int __fsg_is_set(struct fsg_common *common,
|
|
|
if (common->fsg)
|
|
|
return 1;
|
|
|
ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
|
|
|
+ WARN_ON(1);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1392,43 +1410,55 @@ static int do_start_stop(struct fsg_common *common)
|
|
|
} else if (!curlun->removable) {
|
|
|
curlun->sense_data = SS_INVALID_COMMAND;
|
|
|
return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- loej = common->cmnd[4] & 0x02;
|
|
|
- start = common->cmnd[4] & 0x01;
|
|
|
-
|
|
|
- /* eject code from file_storage.c:do_start_stop() */
|
|
|
-
|
|
|
- if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
|
|
|
- (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
|
|
|
+ } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
|
|
|
+ (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
|
|
|
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (!start) {
|
|
|
- /* Are we allowed to unload the media? */
|
|
|
- if (curlun->prevent_medium_removal) {
|
|
|
- LDBG(curlun, "unload attempt prevented\n");
|
|
|
- curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- if (loej) { /* Simulate an unload/eject */
|
|
|
- up_read(&common->filesem);
|
|
|
- down_write(&common->filesem);
|
|
|
- fsg_lun_close(curlun);
|
|
|
- up_write(&common->filesem);
|
|
|
- down_read(&common->filesem);
|
|
|
- }
|
|
|
- } else {
|
|
|
+ loej = common->cmnd[4] & 0x02;
|
|
|
+ start = common->cmnd[4] & 0x01;
|
|
|
|
|
|
- /* Our emulation doesn't support mounting; the medium is
|
|
|
- * available for use as soon as it is loaded. */
|
|
|
+ /* Our emulation doesn't support mounting; the medium is
|
|
|
+ * available for use as soon as it is loaded. */
|
|
|
+ if (start) {
|
|
|
if (!fsg_lun_is_open(curlun)) {
|
|
|
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
+ return 0;
|
|
|
}
|
|
|
- return 0;
|
|
|
+
|
|
|
+ /* Are we allowed to unload the media? */
|
|
|
+ if (curlun->prevent_medium_removal) {
|
|
|
+ LDBG(curlun, "unload attempt prevented\n");
|
|
|
+ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2607,7 +2637,8 @@ static int fsg_main_thread(void *common_)
|
|
|
common->thread_task = NULL;
|
|
|
spin_unlock_irq(&common->lock);
|
|
|
|
|
|
- if (!common->thread_exits || common->thread_exits(common) < 0) {
|
|
|
+ if (!common->ops || !common->ops->thread_exits
|
|
|
+ || common->ops->thread_exits(common) < 0) {
|
|
|
struct fsg_lun *curlun = common->luns;
|
|
|
unsigned i = common->nluns;
|
|
|
|
|
@@ -2683,6 +2714,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|
|
common->free_storage_on_release = 0;
|
|
|
}
|
|
|
|
|
|
+ common->ops = cfg->ops;
|
|
|
common->private_data = cfg->private_data;
|
|
|
|
|
|
common->gadget = gadget;
|
|
@@ -2804,7 +2836,6 @@ buffhds_first_it:
|
|
|
|
|
|
|
|
|
/* Tell the thread to start working */
|
|
|
- common->thread_exits = cfg->thread_exits;
|
|
|
common->thread_task =
|
|
|
kthread_create(fsg_main_thread, common,
|
|
|
OR(cfg->thread_name, "file-storage"));
|
|
@@ -3100,8 +3131,8 @@ fsg_config_from_params(struct fsg_config *cfg,
|
|
|
cfg->product_name = 0;
|
|
|
cfg->release = 0xffff;
|
|
|
|
|
|
- cfg->thread_exits = 0;
|
|
|
- cfg->private_data = 0;
|
|
|
+ cfg->ops = NULL;
|
|
|
+ cfg->private_data = NULL;
|
|
|
|
|
|
/* Finalise */
|
|
|
cfg->can_stall = params->stall;
|