aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/f_mass_storage.c109
-rw-r--r--drivers/usb/gadget/mass_storage.c5
2 files changed, 74 insertions, 40 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index fa86b946dcd6..32cce029f65c 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -316,6 +316,27 @@ static const char fsg_string_interface[] = "Mass Storage";
316/*-------------------------------------------------------------------------*/ 316/*-------------------------------------------------------------------------*/
317 317
318struct fsg_dev; 318struct fsg_dev;
319struct fsg_common;
320
321/* FSF callback functions */
322struct fsg_operations {
323 /* Callback function to call when thread exits. If no
324 * callback is set or it returns value lower then zero MSF
325 * will force eject all LUNs it operates on (including those
326 * marked as non-removable or with prevent_medium_removal flag
327 * set). */
328 int (*thread_exits)(struct fsg_common *common);
329
330 /* Called prior to ejection. Negative return means error,
331 * zero means to continue with ejection, positive means not to
332 * eject. */
333 int (*pre_eject)(struct fsg_common *common,
334 struct fsg_lun *lun, int num);
335 /* Called after ejection. Negative return means error, zero
336 * or positive is just a success. */
337 int (*post_eject)(struct fsg_common *common,
338 struct fsg_lun *lun, int num);
339};
319 340
320 341
321/* Data shared by all the FSG instances. */ 342/* Data shared by all the FSG instances. */
@@ -368,8 +389,8 @@ struct fsg_common {
368 struct completion thread_notifier; 389 struct completion thread_notifier;
369 struct task_struct *thread_task; 390 struct task_struct *thread_task;
370 391
371 /* Callback function to call when thread exits. */ 392 /* Callback functions. */
372 int (*thread_exits)(struct fsg_common *common); 393 const struct fsg_operations *ops;
373 /* Gadget's private data. */ 394 /* Gadget's private data. */
374 void *private_data; 395 void *private_data;
375 396
@@ -393,12 +414,8 @@ struct fsg_config {
393 const char *lun_name_format; 414 const char *lun_name_format;
394 const char *thread_name; 415 const char *thread_name;
395 416
396 /* Callback function to call when thread exits. If no 417 /* Callback functions. */
397 * callback is set or it returns value lower then zero MSF 418 const struct fsg_operations *ops;
398 * will force eject all LUNs it operates on (including those
399 * marked as non-removable or with prevent_medium_removal flag
400 * set). */
401 int (*thread_exits)(struct fsg_common *common);
402 /* Gadget's private data. */ 419 /* Gadget's private data. */
403 void *private_data; 420 void *private_data;
404 421
@@ -434,6 +451,7 @@ static inline int __fsg_is_set(struct fsg_common *common,
434 if (common->fsg) 451 if (common->fsg)
435 return 1; 452 return 1;
436 ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); 453 ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
454 WARN_ON(1);
437 return 0; 455 return 0;
438} 456}
439 457
@@ -1392,43 +1410,55 @@ static int do_start_stop(struct fsg_common *common)
1392 } else if (!curlun->removable) { 1410 } else if (!curlun->removable) {
1393 curlun->sense_data = SS_INVALID_COMMAND; 1411 curlun->sense_data = SS_INVALID_COMMAND;
1394 return -EINVAL; 1412 return -EINVAL;
1395 } 1413 } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
1396 1414 (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
1397 loej = common->cmnd[4] & 0x02;
1398 start = common->cmnd[4] & 0x01;
1399
1400 /* eject code from file_storage.c:do_start_stop() */
1401
1402 if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
1403 (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
1404 curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1415 curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
1405 return -EINVAL; 1416 return -EINVAL;
1406 } 1417 }
1407 1418
1408 if (!start) { 1419 loej = common->cmnd[4] & 0x02;
1409 /* Are we allowed to unload the media? */ 1420 start = common->cmnd[4] & 0x01;
1410 if (curlun->prevent_medium_removal) {
1411 LDBG(curlun, "unload attempt prevented\n");
1412 curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
1413 return -EINVAL;
1414 }
1415 if (loej) { /* Simulate an unload/eject */
1416 up_read(&common->filesem);
1417 down_write(&common->filesem);
1418 fsg_lun_close(curlun);
1419 up_write(&common->filesem);
1420 down_read(&common->filesem);
1421 }
1422 } else {
1423 1421
1424 /* Our emulation doesn't support mounting; the medium is 1422 /* Our emulation doesn't support mounting; the medium is
1425 * available for use as soon as it is loaded. */ 1423 * available for use as soon as it is loaded. */
1424 if (start) {
1426 if (!fsg_lun_is_open(curlun)) { 1425 if (!fsg_lun_is_open(curlun)) {
1427 curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 1426 curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
1428 return -EINVAL; 1427 return -EINVAL;
1429 } 1428 }
1429 return 0;
1430 } 1430 }
1431 return 0; 1431
1432 /* Are we allowed to unload the media? */
1433 if (curlun->prevent_medium_removal) {
1434 LDBG(curlun, "unload attempt prevented\n");
1435 curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
1436 return -EINVAL;
1437 }
1438
1439 if (!loej)
1440 return 0;
1441
1442 /* Simulate an unload/eject */
1443 if (common->ops && common->ops->pre_eject) {
1444 int r = common->ops->pre_eject(common, curlun,
1445 curlun - common->luns);
1446 if (unlikely(r < 0))
1447 return r;
1448 else if (r)
1449 return 0;
1450 }
1451
1452 up_read(&common->filesem);
1453 down_write(&common->filesem);
1454 fsg_lun_close(curlun);
1455 up_write(&common->filesem);
1456 down_read(&common->filesem);
1457
1458 return common->ops && common->ops->post_eject
1459 ? min(0, common->ops->post_eject(common, curlun,
1460 curlun - common->luns))
1461 : 0;
1432} 1462}
1433 1463
1434 1464
@@ -2607,7 +2637,8 @@ static int fsg_main_thread(void *common_)
2607 common->thread_task = NULL; 2637 common->thread_task = NULL;
2608 spin_unlock_irq(&common->lock); 2638 spin_unlock_irq(&common->lock);
2609 2639
2610 if (!common->thread_exits || common->thread_exits(common) < 0) { 2640 if (!common->ops || !common->ops->thread_exits
2641 || common->ops->thread_exits(common) < 0) {
2611 struct fsg_lun *curlun = common->luns; 2642 struct fsg_lun *curlun = common->luns;
2612 unsigned i = common->nluns; 2643 unsigned i = common->nluns;
2613 2644
@@ -2683,6 +2714,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
2683 common->free_storage_on_release = 0; 2714 common->free_storage_on_release = 0;
2684 } 2715 }
2685 2716
2717 common->ops = cfg->ops;
2686 common->private_data = cfg->private_data; 2718 common->private_data = cfg->private_data;
2687 2719
2688 common->gadget = gadget; 2720 common->gadget = gadget;
@@ -2804,7 +2836,6 @@ buffhds_first_it:
2804 2836
2805 2837
2806 /* Tell the thread to start working */ 2838 /* Tell the thread to start working */
2807 common->thread_exits = cfg->thread_exits;
2808 common->thread_task = 2839 common->thread_task =
2809 kthread_create(fsg_main_thread, common, 2840 kthread_create(fsg_main_thread, common,
2810 OR(cfg->thread_name, "file-storage")); 2841 OR(cfg->thread_name, "file-storage"));
@@ -3100,8 +3131,8 @@ fsg_config_from_params(struct fsg_config *cfg,
3100 cfg->product_name = 0; 3131 cfg->product_name = 0;
3101 cfg->release = 0xffff; 3132 cfg->release = 0xffff;
3102 3133
3103 cfg->thread_exits = 0; 3134 cfg->ops = NULL;
3104 cfg->private_data = 0; 3135 cfg->private_data = NULL;
3105 3136
3106 /* Finalise */ 3137 /* Finalise */
3107 cfg->can_stall = params->stall; 3138 cfg->can_stall = params->stall;
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 2b11e2079823..306098f2d924 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -143,6 +143,9 @@ static int msg_thread_exits(struct fsg_common *common)
143 143
144static int __init msg_do_config(struct usb_configuration *c) 144static int __init msg_do_config(struct usb_configuration *c)
145{ 145{
146 static const struct fsg_operations ops = {
147 .thread_exits = msg_thread_exits,
148 };
146 static struct fsg_common common; 149 static struct fsg_common common;
147 150
148 struct fsg_common *retp; 151 struct fsg_common *retp;
@@ -155,7 +158,7 @@ static int __init msg_do_config(struct usb_configuration *c)
155 } 158 }
156 159
157 fsg_config_from_params(&config, &mod_data); 160 fsg_config_from_params(&config, &mod_data);
158 config.thread_exits = msg_thread_exits; 161 config.ops = &ops;
159 162
160 retp = fsg_common_init(&common, c->cdev, &config); 163 retp = fsg_common_init(&common, c->cdev, &config);
161 if (IS_ERR(retp)) 164 if (IS_ERR(retp))