summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/f_mass_storage.c63
-rw-r--r--drivers/usb/gadget/file_storage.c50
-rw-r--r--drivers/usb/gadget/storage_common.c23
3 files changed, 79 insertions, 57 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 4ce3dec..1cdb1fa 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -112,8 +112,7 @@
* is not loaded (an empty string as "filename" in the fsg_config
* structure causes error). The CD-ROM emulation includes a single
* data track and no audio tracks; hence there need be only one
- * backing file per LUN. Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
*
*
* MSF includes support for module parameters. If gadget using it
@@ -771,7 +770,7 @@ static int do_read(struct fsg_common *common)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
@@ -812,7 +811,8 @@ static int do_read(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -835,7 +835,7 @@ static int do_read(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int)nread, amount);
- nread -= (nread & 511); /* Round down to a block */
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
@@ -846,7 +846,8 @@ static int do_read(struct fsg_common *common)
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -921,7 +922,7 @@ static int do_write(struct fsg_common *common)
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
@@ -954,11 +955,12 @@ static int do_write(struct fsg_common *common)
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info =
+ usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= amount & 511;
+ amount = round_down(amount, curlun->blksize);
if (amount == 0) {
/*
@@ -1002,7 +1004,8 @@ static int do_write(struct fsg_common *common)
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1033,8 +1036,7 @@ static int do_write(struct fsg_common *common)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int)nwritten, amount);
- nwritten -= (nwritten & 511);
- /* Round down to a block */
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1043,7 +1045,8 @@ static int do_write(struct fsg_common *common)
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1129,8 +1132,8 @@ static int do_verify(struct fsg_common *common)
return -EIO; /* No default reply */
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1157,7 +1160,8 @@ static int do_verify(struct fsg_common *common)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1179,11 +1183,12 @@ static int do_verify(struct fsg_common *common)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int)nread, amount);
- nread -= nread & 511; /* Round down to a sector */
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1289,7 +1294,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
return 8;
}
@@ -1527,7 +1532,7 @@ static int do_read_format_capacities(struct fsg_common *common,
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -2022,7 +2027,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)");
@@ -2032,7 +2038,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)");
@@ -2042,7 +2049,8 @@ static int do_scsi_command(struct fsg_common *common)
case READ_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)");
@@ -2142,7 +2150,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)");
@@ -2152,7 +2161,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
@@ -2162,7 +2172,8 @@ static int do_scsi_command(struct fsg_common *common)
case WRITE_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)");
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 39ece40..59d9775 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -69,8 +69,7 @@
* each LUN would be settable independently as a disk drive or a CD-ROM
* drive, but currently all LUNs have to be the same type. The CD-ROM
* emulation includes a single data track and no audio tracks; hence there
- * need be only one backing file per LUN. Note also that the CD-ROM block
- * length is set to 512 rather than the more common value 2048.
+ * need be only one backing file per LUN.
*
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
* needed (an interrupt-out endpoint is also needed for CBI). The memory
@@ -1158,7 +1157,7 @@ static int do_read(struct fsg_dev *fsg)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = fsg->data_size_from_cmnd;
@@ -1196,7 +1195,7 @@ static int do_read(struct fsg_dev *fsg)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -1221,7 +1220,7 @@ static int do_read(struct fsg_dev *fsg)
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a block
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
@@ -1232,7 +1231,7 @@ static int do_read(struct fsg_dev *fsg)
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1303,7 +1302,7 @@ static int do_write(struct fsg_dev *fsg)
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
while (amount_left_to_write > 0) {
@@ -1333,11 +1332,11 @@ static int do_write(struct fsg_dev *fsg)
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info = usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= (amount & 511);
+ amount = round_down(amount, curlun->blksize);
if (amount == 0) {
/* Why were we were asked to transfer a
@@ -1376,7 +1375,7 @@ static int do_write(struct fsg_dev *fsg)
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1408,8 +1407,7 @@ static int do_write(struct fsg_dev *fsg)
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int) nwritten, amount);
- nwritten -= (nwritten & 511);
- // Round down to a block
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1418,7 +1416,7 @@ static int do_write(struct fsg_dev *fsg)
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1500,8 +1498,8 @@ static int do_verify(struct fsg_dev *fsg)
return -EIO; // No default reply
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1527,7 +1525,7 @@ static int do_verify(struct fsg_dev *fsg)
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1550,11 +1548,11 @@ static int do_verify(struct fsg_dev *fsg)
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a sector
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1668,7 +1666,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
return 8;
}
@@ -1890,7 +1888,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -2415,7 +2413,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)")) == 0)
@@ -2424,7 +2422,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)")) == 0)
@@ -2433,7 +2431,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case READ_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)")) == 0)
@@ -2519,7 +2517,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)")) == 0)
@@ -2528,7 +2526,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)")) == 0)
@@ -2537,7 +2535,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case WRITE_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)")) == 0)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index d3dd227..3ea70d8 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -247,6 +247,8 @@ struct fsg_lun {
u32 sense_data_info;
u32 unit_attention_data;
+ unsigned int blkbits; /* Bits of logical block size of bound block device */
+ unsigned int blksize; /* logical block size of bound block device */
struct device dev;
};
@@ -580,13 +582,24 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
rc = (int) size;
goto out;
}
- num_sectors = size >> 9; /* File size in 512-byte blocks */
+
+ if (curlun->cdrom) {
+ curlun->blksize = 2048;
+ curlun->blkbits = 11;
+ } else if (inode->i_bdev) {
+ curlun->blksize = bdev_logical_block_size(inode->i_bdev);
+ curlun->blkbits = blksize_bits(curlun->blksize);
+ } else {
+ curlun->blksize = 512;
+ curlun->blkbits = 9;
+ }
+
+ num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
min_sectors = 1;
if (curlun->cdrom) {
- num_sectors &= ~3; /* Reduce to a multiple of 2048 */
- min_sectors = 300*4; /* Smallest track is 300 frames */
- if (num_sectors >= 256*60*75*4) {
- num_sectors = (256*60*75 - 1) * 4;
+ min_sectors = 300; /* Smallest track is 300 frames */
+ if (num_sectors >= 256*60*75) {
+ num_sectors = 256*60*75 - 1;
LINFO(curlun, "file too big: %s\n", filename);
LINFO(curlun, "using only first %d blocks\n",
(int) num_sectors);
OpenPOWER on IntegriCloud