|
@@ -69,8 +69,7 @@
|
|
* each LUN would be settable independently as a disk drive or a CD-ROM
|
|
* 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
|
|
* 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
|
|
* 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
|
|
* 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
|
|
* needed (an interrupt-out endpoint is also needed for CBI). The memory
|
|
@@ -461,7 +460,6 @@ struct fsg_dev {
|
|
|
|
|
|
struct fsg_buffhd *next_buffhd_to_fill;
|
|
struct fsg_buffhd *next_buffhd_to_fill;
|
|
struct fsg_buffhd *next_buffhd_to_drain;
|
|
struct fsg_buffhd *next_buffhd_to_drain;
|
|
- struct fsg_buffhd buffhds[FSG_NUM_BUFFERS];
|
|
|
|
|
|
|
|
int thread_wakeup_needed;
|
|
int thread_wakeup_needed;
|
|
struct completion thread_notifier;
|
|
struct completion thread_notifier;
|
|
@@ -488,6 +486,8 @@ struct fsg_dev {
|
|
unsigned int nluns;
|
|
unsigned int nluns;
|
|
struct fsg_lun *luns;
|
|
struct fsg_lun *luns;
|
|
struct fsg_lun *curlun;
|
|
struct fsg_lun *curlun;
|
|
|
|
+ /* Must be the last entry */
|
|
|
|
+ struct fsg_buffhd buffhds[];
|
|
};
|
|
};
|
|
|
|
|
|
typedef void (*fsg_routine_t)(struct fsg_dev *);
|
|
typedef void (*fsg_routine_t)(struct fsg_dev *);
|
|
@@ -1136,7 +1136,6 @@ static int do_read(struct fsg_dev *fsg)
|
|
u32 amount_left;
|
|
u32 amount_left;
|
|
loff_t file_offset, file_offset_tmp;
|
|
loff_t file_offset, file_offset_tmp;
|
|
unsigned int amount;
|
|
unsigned int amount;
|
|
- unsigned int partial_page;
|
|
|
|
ssize_t nread;
|
|
ssize_t nread;
|
|
|
|
|
|
/* Get the starting Logical Block Address and check that it's
|
|
/* Get the starting Logical Block Address and check that it's
|
|
@@ -1158,7 +1157,7 @@ static int do_read(struct fsg_dev *fsg)
|
|
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
- file_offset = ((loff_t) lba) << 9;
|
|
|
|
|
|
+ file_offset = ((loff_t) lba) << curlun->blkbits;
|
|
|
|
|
|
/* Carry out the file reads */
|
|
/* Carry out the file reads */
|
|
amount_left = fsg->data_size_from_cmnd;
|
|
amount_left = fsg->data_size_from_cmnd;
|
|
@@ -1171,17 +1170,10 @@ static int do_read(struct fsg_dev *fsg)
|
|
* Try to read the remaining amount.
|
|
* Try to read the remaining amount.
|
|
* But don't read more than the buffer size.
|
|
* But don't read more than the buffer size.
|
|
* And don't try to read past the end of the file.
|
|
* And don't try to read past the end of the file.
|
|
- * Finally, if we're not at a page boundary, don't read past
|
|
|
|
- * the next page.
|
|
|
|
- * If this means reading 0 then we were asked to read past
|
|
|
|
- * the end of file. */
|
|
|
|
|
|
+ */
|
|
amount = min((unsigned int) amount_left, mod_data.buflen);
|
|
amount = min((unsigned int) amount_left, mod_data.buflen);
|
|
amount = min((loff_t) amount,
|
|
amount = min((loff_t) amount,
|
|
curlun->file_length - file_offset);
|
|
curlun->file_length - file_offset);
|
|
- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
|
|
|
|
- if (partial_page > 0)
|
|
|
|
- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
|
|
|
|
- partial_page);
|
|
|
|
|
|
|
|
/* Wait for the next buffer to become available */
|
|
/* Wait for the next buffer to become available */
|
|
bh = fsg->next_buffhd_to_fill;
|
|
bh = fsg->next_buffhd_to_fill;
|
|
@@ -1196,7 +1188,7 @@ static int do_read(struct fsg_dev *fsg)
|
|
if (amount == 0) {
|
|
if (amount == 0) {
|
|
curlun->sense_data =
|
|
curlun->sense_data =
|
|
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
bh->inreq->length = 0;
|
|
bh->inreq->length = 0;
|
|
bh->state = BUF_STATE_FULL;
|
|
bh->state = BUF_STATE_FULL;
|
|
@@ -1221,18 +1213,23 @@ static int do_read(struct fsg_dev *fsg)
|
|
} else if (nread < amount) {
|
|
} else if (nread < amount) {
|
|
LDBG(curlun, "partial file read: %d/%u\n",
|
|
LDBG(curlun, "partial file read: %d/%u\n",
|
|
(int) nread, amount);
|
|
(int) nread, amount);
|
|
- nread -= (nread & 511); // Round down to a block
|
|
|
|
|
|
+ nread = round_down(nread, curlun->blksize);
|
|
}
|
|
}
|
|
file_offset += nread;
|
|
file_offset += nread;
|
|
amount_left -= nread;
|
|
amount_left -= nread;
|
|
fsg->residue -= nread;
|
|
fsg->residue -= nread;
|
|
|
|
+
|
|
|
|
+ /* Except at the end of the transfer, nread will be
|
|
|
|
+ * equal to the buffer size, which is divisible by the
|
|
|
|
+ * bulk-in maxpacket size.
|
|
|
|
+ */
|
|
bh->inreq->length = nread;
|
|
bh->inreq->length = nread;
|
|
bh->state = BUF_STATE_FULL;
|
|
bh->state = BUF_STATE_FULL;
|
|
|
|
|
|
/* If an error occurred, report it and its position */
|
|
/* If an error occurred, report it and its position */
|
|
if (nread < amount) {
|
|
if (nread < amount) {
|
|
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1262,7 +1259,6 @@ static int do_write(struct fsg_dev *fsg)
|
|
u32 amount_left_to_req, amount_left_to_write;
|
|
u32 amount_left_to_req, amount_left_to_write;
|
|
loff_t usb_offset, file_offset, file_offset_tmp;
|
|
loff_t usb_offset, file_offset, file_offset_tmp;
|
|
unsigned int amount;
|
|
unsigned int amount;
|
|
- unsigned int partial_page;
|
|
|
|
ssize_t nwritten;
|
|
ssize_t nwritten;
|
|
int rc;
|
|
int rc;
|
|
|
|
|
|
@@ -1303,7 +1299,7 @@ static int do_write(struct fsg_dev *fsg)
|
|
|
|
|
|
/* Carry out the file writes */
|
|
/* Carry out the file writes */
|
|
get_some_more = 1;
|
|
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;
|
|
amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
|
|
|
|
|
|
while (amount_left_to_write > 0) {
|
|
while (amount_left_to_write > 0) {
|
|
@@ -1313,38 +1309,20 @@ static int do_write(struct fsg_dev *fsg)
|
|
if (bh->state == BUF_STATE_EMPTY && get_some_more) {
|
|
if (bh->state == BUF_STATE_EMPTY && get_some_more) {
|
|
|
|
|
|
/* Figure out how much we want to get:
|
|
/* Figure out how much we want to get:
|
|
- * Try to get the remaining amount.
|
|
|
|
- * But don't get more than the buffer size.
|
|
|
|
- * And don't try to go past the end of the file.
|
|
|
|
- * If we're not at a page boundary,
|
|
|
|
- * don't go past the next page.
|
|
|
|
- * If this means getting 0, then we were asked
|
|
|
|
- * to write past the end of file.
|
|
|
|
- * Finally, round down to a block boundary. */
|
|
|
|
|
|
+ * Try to get the remaining amount,
|
|
|
|
+ * but not more than the buffer size.
|
|
|
|
+ */
|
|
amount = min(amount_left_to_req, mod_data.buflen);
|
|
amount = min(amount_left_to_req, mod_data.buflen);
|
|
- amount = min((loff_t) amount, curlun->file_length -
|
|
|
|
- usb_offset);
|
|
|
|
- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
|
|
|
|
- if (partial_page > 0)
|
|
|
|
- amount = min(amount,
|
|
|
|
- (unsigned int) PAGE_CACHE_SIZE - partial_page);
|
|
|
|
-
|
|
|
|
- if (amount == 0) {
|
|
|
|
|
|
+
|
|
|
|
+ /* Beyond the end of the backing file? */
|
|
|
|
+ if (usb_offset >= curlun->file_length) {
|
|
get_some_more = 0;
|
|
get_some_more = 0;
|
|
curlun->sense_data =
|
|
curlun->sense_data =
|
|
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
- amount -= (amount & 511);
|
|
|
|
- if (amount == 0) {
|
|
|
|
-
|
|
|
|
- /* Why were we were asked to transfer a
|
|
|
|
- * partial block? */
|
|
|
|
- get_some_more = 0;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
|
|
|
|
/* Get the next buffer */
|
|
/* Get the next buffer */
|
|
usb_offset += amount;
|
|
usb_offset += amount;
|
|
@@ -1353,8 +1331,10 @@ static int do_write(struct fsg_dev *fsg)
|
|
if (amount_left_to_req == 0)
|
|
if (amount_left_to_req == 0)
|
|
get_some_more = 0;
|
|
get_some_more = 0;
|
|
|
|
|
|
- /* amount is always divisible by 512, hence by
|
|
|
|
- * the bulk-out maxpacket size */
|
|
|
|
|
|
+ /* Except at the end of the transfer, amount will be
|
|
|
|
+ * equal to the buffer size, which is divisible by
|
|
|
|
+ * the bulk-out maxpacket size.
|
|
|
|
+ */
|
|
bh->outreq->length = bh->bulk_out_intended_length =
|
|
bh->outreq->length = bh->bulk_out_intended_length =
|
|
amount;
|
|
amount;
|
|
bh->outreq->short_not_ok = 1;
|
|
bh->outreq->short_not_ok = 1;
|
|
@@ -1376,7 +1356,7 @@ static int do_write(struct fsg_dev *fsg)
|
|
/* Did something go wrong with the transfer? */
|
|
/* Did something go wrong with the transfer? */
|
|
if (bh->outreq->status != 0) {
|
|
if (bh->outreq->status != 0) {
|
|
curlun->sense_data = SS_COMMUNICATION_FAILURE;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1390,6 +1370,11 @@ static int do_write(struct fsg_dev *fsg)
|
|
amount = curlun->file_length - file_offset;
|
|
amount = curlun->file_length - file_offset;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Don't write a partial block */
|
|
|
|
+ amount = round_down(amount, curlun->blksize);
|
|
|
|
+ if (amount == 0)
|
|
|
|
+ goto empty_write;
|
|
|
|
+
|
|
/* Perform the write */
|
|
/* Perform the write */
|
|
file_offset_tmp = file_offset;
|
|
file_offset_tmp = file_offset;
|
|
nwritten = vfs_write(curlun->filp,
|
|
nwritten = vfs_write(curlun->filp,
|
|
@@ -1408,8 +1393,7 @@ static int do_write(struct fsg_dev *fsg)
|
|
} else if (nwritten < amount) {
|
|
} else if (nwritten < amount) {
|
|
LDBG(curlun, "partial file write: %d/%u\n",
|
|
LDBG(curlun, "partial file write: %d/%u\n",
|
|
(int) nwritten, amount);
|
|
(int) nwritten, amount);
|
|
- nwritten -= (nwritten & 511);
|
|
|
|
- // Round down to a block
|
|
|
|
|
|
+ nwritten = round_down(nwritten, curlun->blksize);
|
|
}
|
|
}
|
|
file_offset += nwritten;
|
|
file_offset += nwritten;
|
|
amount_left_to_write -= nwritten;
|
|
amount_left_to_write -= nwritten;
|
|
@@ -1418,11 +1402,12 @@ static int do_write(struct fsg_dev *fsg)
|
|
/* If an error occurred, report it and its position */
|
|
/* If an error occurred, report it and its position */
|
|
if (nwritten < amount) {
|
|
if (nwritten < amount) {
|
|
curlun->sense_data = SS_WRITE_ERROR;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ empty_write:
|
|
/* Did the host decide to stop early? */
|
|
/* Did the host decide to stop early? */
|
|
if (bh->outreq->actual != bh->outreq->length) {
|
|
if (bh->outreq->actual != bh->outreq->length) {
|
|
fsg->short_packet_received = 1;
|
|
fsg->short_packet_received = 1;
|
|
@@ -1500,8 +1485,8 @@ static int do_verify(struct fsg_dev *fsg)
|
|
return -EIO; // No default reply
|
|
return -EIO; // No default reply
|
|
|
|
|
|
/* Prepare to carry out the file verify */
|
|
/* 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 */
|
|
/* Write out all the dirty buffers before invalidating them */
|
|
fsg_lun_fsync_sub(curlun);
|
|
fsg_lun_fsync_sub(curlun);
|
|
@@ -1519,15 +1504,14 @@ static int do_verify(struct fsg_dev *fsg)
|
|
* Try to read the remaining amount, but not more than
|
|
* Try to read the remaining amount, but not more than
|
|
* the buffer size.
|
|
* the buffer size.
|
|
* And don't try to read past the end of the file.
|
|
* And don't try to read past the end of the file.
|
|
- * If this means reading 0 then we were asked to read
|
|
|
|
- * past the end of file. */
|
|
|
|
|
|
+ */
|
|
amount = min((unsigned int) amount_left, mod_data.buflen);
|
|
amount = min((unsigned int) amount_left, mod_data.buflen);
|
|
amount = min((loff_t) amount,
|
|
amount = min((loff_t) amount,
|
|
curlun->file_length - file_offset);
|
|
curlun->file_length - file_offset);
|
|
if (amount == 0) {
|
|
if (amount == 0) {
|
|
curlun->sense_data =
|
|
curlun->sense_data =
|
|
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1550,11 +1534,11 @@ static int do_verify(struct fsg_dev *fsg)
|
|
} else if (nread < amount) {
|
|
} else if (nread < amount) {
|
|
LDBG(curlun, "partial file verify: %d/%u\n",
|
|
LDBG(curlun, "partial file verify: %d/%u\n",
|
|
(int) nread, amount);
|
|
(int) nread, amount);
|
|
- nread -= (nread & 511); // Round down to a sector
|
|
|
|
|
|
+ nread = round_down(nread, curlun->blksize);
|
|
}
|
|
}
|
|
if (nread == 0) {
|
|
if (nread == 0) {
|
|
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
|
|
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;
|
|
curlun->info_valid = 1;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1668,7 +1652,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
|
|
|
|
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
|
|
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
|
|
/* Max logical block */
|
|
/* Max logical block */
|
|
- put_unaligned_be32(512, &buf[4]); /* Block length */
|
|
|
|
|
|
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
|
|
return 8;
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1890,7 +1874,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
|
|
|
|
|
|
put_unaligned_be32(curlun->num_sectors, &buf[0]);
|
|
put_unaligned_be32(curlun->num_sectors, &buf[0]);
|
|
/* Number of blocks */
|
|
/* 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 */
|
|
buf[4] = 0x02; /* Current capacity */
|
|
return 12;
|
|
return 12;
|
|
}
|
|
}
|
|
@@ -1983,8 +1967,10 @@ static int throw_away_data(struct fsg_dev *fsg)
|
|
amount = min(fsg->usb_amount_left,
|
|
amount = min(fsg->usb_amount_left,
|
|
(u32) mod_data.buflen);
|
|
(u32) mod_data.buflen);
|
|
|
|
|
|
- /* amount is always divisible by 512, hence by
|
|
|
|
- * the bulk-out maxpacket size */
|
|
|
|
|
|
+ /* Except at the end of the transfer, amount will be
|
|
|
|
+ * equal to the buffer size, which is divisible by
|
|
|
|
+ * the bulk-out maxpacket size.
|
|
|
|
+ */
|
|
bh->outreq->length = bh->bulk_out_intended_length =
|
|
bh->outreq->length = bh->bulk_out_intended_length =
|
|
amount;
|
|
amount;
|
|
bh->outreq->short_not_ok = 1;
|
|
bh->outreq->short_not_ok = 1;
|
|
@@ -2415,7 +2401,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case READ_6:
|
|
case READ_6:
|
|
i = fsg->cmnd[4];
|
|
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,
|
|
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
|
(7<<1) | (1<<4), 1,
|
|
(7<<1) | (1<<4), 1,
|
|
"READ(6)")) == 0)
|
|
"READ(6)")) == 0)
|
|
@@ -2424,7 +2410,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case READ_10:
|
|
case READ_10:
|
|
fsg->data_size_from_cmnd =
|
|
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,
|
|
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
|
(1<<1) | (0xf<<2) | (3<<7), 1,
|
|
(1<<1) | (0xf<<2) | (3<<7), 1,
|
|
"READ(10)")) == 0)
|
|
"READ(10)")) == 0)
|
|
@@ -2433,7 +2419,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case READ_12:
|
|
case READ_12:
|
|
fsg->data_size_from_cmnd =
|
|
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,
|
|
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
|
|
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
|
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
|
"READ(12)")) == 0)
|
|
"READ(12)")) == 0)
|
|
@@ -2519,7 +2505,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case WRITE_6:
|
|
case WRITE_6:
|
|
i = fsg->cmnd[4];
|
|
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,
|
|
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
|
|
(7<<1) | (1<<4), 1,
|
|
(7<<1) | (1<<4), 1,
|
|
"WRITE(6)")) == 0)
|
|
"WRITE(6)")) == 0)
|
|
@@ -2528,7 +2514,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case WRITE_10:
|
|
case WRITE_10:
|
|
fsg->data_size_from_cmnd =
|
|
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,
|
|
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
|
|
(1<<1) | (0xf<<2) | (3<<7), 1,
|
|
(1<<1) | (0xf<<2) | (3<<7), 1,
|
|
"WRITE(10)")) == 0)
|
|
"WRITE(10)")) == 0)
|
|
@@ -2537,7 +2523,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
|
|
|
|
case WRITE_12:
|
|
case WRITE_12:
|
|
fsg->data_size_from_cmnd =
|
|
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,
|
|
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
|
|
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
|
(1<<1) | (0xf<<2) | (0xf<<6), 1,
|
|
"WRITE(12)")) == 0)
|
|
"WRITE(12)")) == 0)
|
|
@@ -2752,7 +2738,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
|
|
|
|
|
|
reset:
|
|
reset:
|
|
/* Deallocate the requests */
|
|
/* Deallocate the requests */
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
|
|
|
|
if (bh->inreq) {
|
|
if (bh->inreq) {
|
|
@@ -2813,7 +2799,7 @@ reset:
|
|
}
|
|
}
|
|
|
|
|
|
/* Allocate the requests */
|
|
/* Allocate the requests */
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
|
|
|
|
if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
|
|
if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
|
|
@@ -2902,7 +2888,7 @@ static void handle_exception(struct fsg_dev *fsg)
|
|
/* Cancel all the pending transfers */
|
|
/* Cancel all the pending transfers */
|
|
if (fsg->intreq_busy)
|
|
if (fsg->intreq_busy)
|
|
usb_ep_dequeue(fsg->intr_in, fsg->intreq);
|
|
usb_ep_dequeue(fsg->intr_in, fsg->intreq);
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
bh = &fsg->buffhds[i];
|
|
bh = &fsg->buffhds[i];
|
|
if (bh->inreq_busy)
|
|
if (bh->inreq_busy)
|
|
usb_ep_dequeue(fsg->bulk_in, bh->inreq);
|
|
usb_ep_dequeue(fsg->bulk_in, bh->inreq);
|
|
@@ -2913,7 +2899,7 @@ static void handle_exception(struct fsg_dev *fsg)
|
|
/* Wait until everything is idle */
|
|
/* Wait until everything is idle */
|
|
for (;;) {
|
|
for (;;) {
|
|
num_active = fsg->intreq_busy;
|
|
num_active = fsg->intreq_busy;
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
bh = &fsg->buffhds[i];
|
|
bh = &fsg->buffhds[i];
|
|
num_active += bh->inreq_busy + bh->outreq_busy;
|
|
num_active += bh->inreq_busy + bh->outreq_busy;
|
|
}
|
|
}
|
|
@@ -2935,7 +2921,7 @@ static void handle_exception(struct fsg_dev *fsg)
|
|
* state, and the exception. Then invoke the handler. */
|
|
* state, and the exception. Then invoke the handler. */
|
|
spin_lock_irq(&fsg->lock);
|
|
spin_lock_irq(&fsg->lock);
|
|
|
|
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
bh = &fsg->buffhds[i];
|
|
bh = &fsg->buffhds[i];
|
|
bh->state = BUF_STATE_EMPTY;
|
|
bh->state = BUF_STATE_EMPTY;
|
|
}
|
|
}
|
|
@@ -3165,7 +3151,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
|
|
}
|
|
}
|
|
|
|
|
|
/* Free the data buffers */
|
|
/* Free the data buffers */
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i)
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i)
|
|
kfree(fsg->buffhds[i].buf);
|
|
kfree(fsg->buffhds[i].buf);
|
|
|
|
|
|
/* Free the request and buffer for endpoint 0 */
|
|
/* Free the request and buffer for endpoint 0 */
|
|
@@ -3453,7 +3439,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|
req->complete = ep0_complete;
|
|
req->complete = ep0_complete;
|
|
|
|
|
|
/* Allocate the data buffers */
|
|
/* Allocate the data buffers */
|
|
- for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
|
|
|
|
|
|
+ for (i = 0; i < fsg_num_buffers; ++i) {
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
struct fsg_buffhd *bh = &fsg->buffhds[i];
|
|
|
|
|
|
/* Allocate for the bulk-in endpoint. We assume that
|
|
/* Allocate for the bulk-in endpoint. We assume that
|
|
@@ -3464,7 +3450,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|
goto out;
|
|
goto out;
|
|
bh->next = bh + 1;
|
|
bh->next = bh + 1;
|
|
}
|
|
}
|
|
- fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0];
|
|
|
|
|
|
+ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
|
|
|
|
|
|
/* This should reflect the actual gadget power source */
|
|
/* This should reflect the actual gadget power source */
|
|
usb_gadget_set_selfpowered(gadget);
|
|
usb_gadget_set_selfpowered(gadget);
|
|
@@ -3580,7 +3566,9 @@ static int __init fsg_alloc(void)
|
|
{
|
|
{
|
|
struct fsg_dev *fsg;
|
|
struct fsg_dev *fsg;
|
|
|
|
|
|
- fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
|
|
|
|
|
|
+ fsg = kzalloc(sizeof *fsg +
|
|
|
|
+ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
|
|
|
|
+
|
|
if (!fsg)
|
|
if (!fsg)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
spin_lock_init(&fsg->lock);
|
|
spin_lock_init(&fsg->lock);
|
|
@@ -3598,6 +3586,10 @@ static int __init fsg_init(void)
|
|
int rc;
|
|
int rc;
|
|
struct fsg_dev *fsg;
|
|
struct fsg_dev *fsg;
|
|
|
|
|
|
|
|
+ rc = fsg_num_buffers_validate();
|
|
|
|
+ if (rc != 0)
|
|
|
|
+ return rc;
|
|
|
|
+
|
|
if ((rc = fsg_alloc()) != 0)
|
|
if ((rc = fsg_alloc()) != 0)
|
|
return rc;
|
|
return rc;
|
|
fsg = the_fsg;
|
|
fsg = the_fsg;
|