diff options
| -rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 9dbe86dec332..c904aa39ad84 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c | |||
| @@ -163,6 +163,10 @@ | |||
| 163 | * ro setting are not allowed when the medium is loaded or if CD-ROM | 163 | * ro setting are not allowed when the medium is loaded or if CD-ROM |
| 164 | * emulation is being used. | 164 | * emulation is being used. |
| 165 | * | 165 | * |
| 166 | * When a LUN receive an "eject" SCSI request (Start/Stop Unit), | ||
| 167 | * if the LUN is removable, the backing file is released to simulate | ||
| 168 | * ejection. | ||
| 169 | * | ||
| 166 | * | 170 | * |
| 167 | * This function is heavily based on "File-backed Storage Gadget" by | 171 | * This function is heavily based on "File-backed Storage Gadget" by |
| 168 | * Alan Stern which in turn is heavily based on "Gadget Zero" by David | 172 | * Alan Stern which in turn is heavily based on "Gadget Zero" by David |
| @@ -1384,12 +1388,50 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) | |||
| 1384 | 1388 | ||
| 1385 | static int do_start_stop(struct fsg_common *common) | 1389 | static int do_start_stop(struct fsg_common *common) |
| 1386 | { | 1390 | { |
| 1387 | if (!common->curlun) { | 1391 | struct fsg_lun *curlun = common->curlun; |
| 1392 | int loej, start; | ||
| 1393 | |||
| 1394 | if (!curlun) { | ||
| 1388 | return -EINVAL; | 1395 | return -EINVAL; |
| 1389 | } else if (!common->curlun->removable) { | 1396 | } else if (!curlun->removable) { |
| 1390 | common->curlun->sense_data = SS_INVALID_COMMAND; | 1397 | curlun->sense_data = SS_INVALID_COMMAND; |
| 1398 | return -EINVAL; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | loej = common->cmnd[4] & 0x02; | ||
| 1402 | start = common->cmnd[4] & 0x01; | ||
| 1403 | |||
| 1404 | /* eject code from file_storage.c:do_start_stop() */ | ||
| 1405 | |||
| 1406 | if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ | ||
| 1407 | (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ | ||
| 1408 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB; | ||
| 1391 | return -EINVAL; | 1409 | return -EINVAL; |
| 1392 | } | 1410 | } |
| 1411 | |||
| 1412 | if (!start) { | ||
| 1413 | /* Are we allowed to unload the media? */ | ||
| 1414 | if (curlun->prevent_medium_removal) { | ||
| 1415 | LDBG(curlun, "unload attempt prevented\n"); | ||
| 1416 | curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; | ||
| 1417 | return -EINVAL; | ||
| 1418 | } | ||
| 1419 | if (loej) { /* Simulate an unload/eject */ | ||
| 1420 | up_read(&common->filesem); | ||
| 1421 | down_write(&common->filesem); | ||
| 1422 | fsg_lun_close(curlun); | ||
| 1423 | up_write(&common->filesem); | ||
| 1424 | down_read(&common->filesem); | ||
| 1425 | } | ||
| 1426 | } else { | ||
| 1427 | |||
| 1428 | /* Our emulation doesn't support mounting; the medium is | ||
| 1429 | * available for use as soon as it is loaded. */ | ||
| 1430 | if (!fsg_lun_is_open(curlun)) { | ||
| 1431 | curlun->sense_data = SS_MEDIUM_NOT_PRESENT; | ||
| 1432 | return -EINVAL; | ||
| 1433 | } | ||
| 1434 | } | ||
| 1393 | return 0; | 1435 | return 0; |
| 1394 | } | 1436 | } |
| 1395 | 1437 | ||
