diff options
Diffstat (limited to 'drivers/usb/gadget/file_storage.c')
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 11b5196284ae..e0f30fc70e45 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, | |||
2297 | DBG(fsg, "using LUN %d from CBW, " | 2297 | DBG(fsg, "using LUN %d from CBW, " |
2298 | "not LUN %d from CDB\n", | 2298 | "not LUN %d from CDB\n", |
2299 | fsg->lun, lun); | 2299 | fsg->lun, lun); |
2300 | } else | 2300 | } |
2301 | fsg->lun = lun; // Use LUN from the command | ||
2302 | 2301 | ||
2303 | /* Check the LUN */ | 2302 | /* Check the LUN */ |
2304 | if (fsg->lun < fsg->nluns) { | 2303 | curlun = fsg->curlun; |
2305 | fsg->curlun = curlun = &fsg->luns[fsg->lun]; | 2304 | if (curlun) { |
2306 | if (fsg->cmnd[0] != REQUEST_SENSE) { | 2305 | if (fsg->cmnd[0] != REQUEST_SENSE) { |
2307 | curlun->sense_data = SS_NO_SENSE; | 2306 | curlun->sense_data = SS_NO_SENSE; |
2308 | curlun->sense_data_info = 0; | 2307 | curlun->sense_data_info = 0; |
2309 | curlun->info_valid = 0; | 2308 | curlun->info_valid = 0; |
2310 | } | 2309 | } |
2311 | } else { | 2310 | } else { |
2312 | fsg->curlun = curlun = NULL; | ||
2313 | fsg->bad_lun_okay = 0; | 2311 | fsg->bad_lun_okay = 0; |
2314 | 2312 | ||
2315 | /* INQUIRY and REQUEST SENSE commands are explicitly allowed | 2313 | /* INQUIRY and REQUEST SENSE commands are explicitly allowed |
@@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, | |||
2351 | return 0; | 2349 | return 0; |
2352 | } | 2350 | } |
2353 | 2351 | ||
2352 | /* wrapper of check_command for data size in blocks handling */ | ||
2353 | static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, | ||
2354 | enum data_direction data_dir, unsigned int mask, | ||
2355 | int needs_medium, const char *name) | ||
2356 | { | ||
2357 | if (fsg->curlun) | ||
2358 | fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; | ||
2359 | return check_command(fsg, cmnd_size, data_dir, | ||
2360 | mask, needs_medium, name); | ||
2361 | } | ||
2354 | 2362 | ||
2355 | static int do_scsi_command(struct fsg_dev *fsg) | 2363 | static int do_scsi_command(struct fsg_dev *fsg) |
2356 | { | 2364 | { |
@@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2425 | 2433 | ||
2426 | case READ_6: | 2434 | case READ_6: |
2427 | i = fsg->cmnd[4]; | 2435 | i = fsg->cmnd[4]; |
2428 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; | 2436 | fsg->data_size_from_cmnd = (i == 0) ? 256 : i; |
2429 | if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, | 2437 | if ((reply = check_command_size_in_blocks(fsg, 6, |
2438 | DATA_DIR_TO_HOST, | ||
2430 | (7<<1) | (1<<4), 1, | 2439 | (7<<1) | (1<<4), 1, |
2431 | "READ(6)")) == 0) | 2440 | "READ(6)")) == 0) |
2432 | reply = do_read(fsg); | 2441 | reply = do_read(fsg); |
2433 | break; | 2442 | break; |
2434 | 2443 | ||
2435 | case READ_10: | 2444 | case READ_10: |
2436 | fsg->data_size_from_cmnd = | 2445 | fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); |
2437 | get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; | 2446 | if ((reply = check_command_size_in_blocks(fsg, 10, |
2438 | if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, | 2447 | DATA_DIR_TO_HOST, |
2439 | (1<<1) | (0xf<<2) | (3<<7), 1, | 2448 | (1<<1) | (0xf<<2) | (3<<7), 1, |
2440 | "READ(10)")) == 0) | 2449 | "READ(10)")) == 0) |
2441 | reply = do_read(fsg); | 2450 | reply = do_read(fsg); |
2442 | break; | 2451 | break; |
2443 | 2452 | ||
2444 | case READ_12: | 2453 | case READ_12: |
2445 | fsg->data_size_from_cmnd = | 2454 | fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); |
2446 | get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; | 2455 | if ((reply = check_command_size_in_blocks(fsg, 12, |
2447 | if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, | 2456 | DATA_DIR_TO_HOST, |
2448 | (1<<1) | (0xf<<2) | (0xf<<6), 1, | 2457 | (1<<1) | (0xf<<2) | (0xf<<6), 1, |
2449 | "READ(12)")) == 0) | 2458 | "READ(12)")) == 0) |
2450 | reply = do_read(fsg); | 2459 | reply = do_read(fsg); |
@@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg) | |||
2529 | 2538 | ||
2530 | case WRITE_6: | 2539 | case WRITE_6: |
2531 | i = fsg->cmnd[4]; | 2540 | i = fsg->cmnd[4]; |
2532 | fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; | 2541 | fsg->data_size_from_cmnd = (i == 0) ? 256 : i; |
2533 | if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, | 2542 | if ((reply = check_command_size_in_blocks(fsg, 6, |
2543 | DATA_DIR_FROM_HOST, | ||
2534 | (7<<1) | (1<<4), 1, | 2544 | (7<<1) | (1<<4), 1, |
2535 | "WRITE(6)")) == 0) | 2545 | "WRITE(6)")) == 0) |
2536 | reply = do_write(fsg); | 2546 | reply = do_write(fsg); |
2537 | break; | 2547 | break; |
2538 | 2548 | ||
2539 | case WRITE_10: | 2549 | case WRITE_10: |
2540 | fsg->data_size_from_cmnd = | 2550 | fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); |
2541 | get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; | 2551 | if ((reply = check_command_size_in_blocks(fsg, 10, |
2542 | if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, | 2552 | DATA_DIR_FROM_HOST, |
2543 | (1<<1) | (0xf<<2) | (3<<7), 1, | 2553 | (1<<1) | (0xf<<2) | (3<<7), 1, |
2544 | "WRITE(10)")) == 0) | 2554 | "WRITE(10)")) == 0) |
2545 | reply = do_write(fsg); | 2555 | reply = do_write(fsg); |
2546 | break; | 2556 | break; |
2547 | 2557 | ||
2548 | case WRITE_12: | 2558 | case WRITE_12: |
2549 | fsg->data_size_from_cmnd = | 2559 | fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); |
2550 | get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; | 2560 | if ((reply = check_command_size_in_blocks(fsg, 12, |
2551 | if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, | 2561 | DATA_DIR_FROM_HOST, |
2552 | (1<<1) | (0xf<<2) | (0xf<<6), 1, | 2562 | (1<<1) | (0xf<<2) | (0xf<<6), 1, |
2553 | "WRITE(12)")) == 0) | 2563 | "WRITE(12)")) == 0) |
2554 | reply = do_write(fsg); | 2564 | reply = do_write(fsg); |
@@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg) | |||
2715 | memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); | 2725 | memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); |
2716 | fsg->cbbuf_cmnd_size = 0; | 2726 | fsg->cbbuf_cmnd_size = 0; |
2717 | spin_unlock_irq(&fsg->lock); | 2727 | spin_unlock_irq(&fsg->lock); |
2728 | |||
2729 | /* Use LUN from the command */ | ||
2730 | fsg->lun = fsg->cmnd[1] >> 5; | ||
2718 | } | 2731 | } |
2732 | |||
2733 | /* Update current lun */ | ||
2734 | if (fsg->lun >= 0 && fsg->lun < fsg->nluns) | ||
2735 | fsg->curlun = &fsg->luns[fsg->lun]; | ||
2736 | else | ||
2737 | fsg->curlun = NULL; | ||
2738 | |||
2719 | return rc; | 2739 | return rc; |
2720 | } | 2740 | } |
2721 | 2741 | ||
@@ -3584,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget) | |||
3584 | /*-------------------------------------------------------------------------*/ | 3604 | /*-------------------------------------------------------------------------*/ |
3585 | 3605 | ||
3586 | static struct usb_gadget_driver fsg_driver = { | 3606 | static struct usb_gadget_driver fsg_driver = { |
3587 | .speed = USB_SPEED_SUPER, | 3607 | .max_speed = USB_SPEED_SUPER, |
3588 | .function = (char *) fsg_string_product, | 3608 | .function = (char *) fsg_string_product, |
3589 | .unbind = fsg_unbind, | 3609 | .unbind = fsg_unbind, |
3590 | .disconnect = fsg_disconnect, | 3610 | .disconnect = fsg_disconnect, |