aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorMichal Nazarewicz <m.nazarewicz@samsung.com>2010-06-21 07:57:09 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 17:35:37 -0400
commit8876f5e7d3b2a320777dd4f6f5301d474c97a06c (patch)
tree7203196be21e46bef900a2f89e30a769730083f1 /drivers/usb/gadget
parent3f3e12d050052032a51f75e72e540322e2a7da2b (diff)
USB: gadget: f_mass_storage: added eject callback
Added pre_eject() and post_eject() callbacks which are called before and after removable logical unit is ejected. The first can prevent logical unit from being ejected. This commit also changes the way callbacks are passed to the function from gadget. A fsg_operations structure has been created which lists all callbacks -- this is passed to the fsg_config. This is important because it changes the way thread_exits() callback is passed. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget')
-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))