diff options
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 109 | ||||
-rw-r--r-- | drivers/usb/gadget/mass_storage.c | 5 |
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 | ||
318 | struct fsg_dev; | 318 | struct fsg_dev; |
319 | struct fsg_common; | ||
320 | |||
321 | /* FSF callback functions */ | ||
322 | struct 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 | ||
144 | static int __init msg_do_config(struct usb_configuration *c) | 144 | static 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)) |