summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Zimmerman <Paul.Zimmerman@synopsys.com>2011-09-30 15:26:06 -0700
committerFelipe Balbi <balbi@ti.com>2011-10-13 20:39:52 +0300
commitfe69676530f182bbb1fe0edd027e18751a1a2595 (patch)
treed509a1b7ba5f147909cfb9f379996644249db74b
parentc8933c3f79568263c90a46f06cf80419e6c63c97 (diff)
usb: gadget: storage: fix mass storage gadgets to work with Synopsys UDC
The Synopsys USB device controller requires all OUT transfer request lengths to be aligned to max packet size. The mass storage gadgets do not meet this requirement for Super Speed. The gadgets already have a function which performs this alignment for CBW packets, so use it for data packets too. The alternative would be to implement bounce buffers in the DWC3 driver, but that could have a significant impact on performance. This version is based upon a more-correct patch written by Alan Stern. Signed-off-by: Paul Zimmerman <paulz@synopsys.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/f_mass_storage.c18
-rw-r--r--drivers/usb/gadget/file_storage.c18
2 files changed, 18 insertions, 18 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 756941473148..927ee88278bd 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -958,9 +958,7 @@ static int do_write(struct fsg_common *common)
* equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -995,6 +993,11 @@ static int do_write(struct fsg_common *common)
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
/* Don't write a partial block */
amount = round_down(amount, curlun->blksize);
if (amount == 0)
@@ -1034,7 +1037,7 @@ static int do_write(struct fsg_common *common)
empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
common->short_packet_received = 1;
break;
}
@@ -1592,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common)
common->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(common,
FSG_STATE_ABORT_BULK_OUT);
@@ -1612,9 +1615,7 @@ static int throw_away_data(struct fsg_common *common)
* equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -2289,7 +2290,6 @@ static int get_next_command(struct fsg_common *common)
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 12ac30b21ba6..a230009db734 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1335,9 +1335,7 @@ static int do_write(struct fsg_dev *fsg)
* equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -1370,6 +1368,11 @@ static int do_write(struct fsg_dev *fsg)
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
/* Don't write a partial block */
amount = round_down(amount, curlun->blksize);
if (amount == 0)
@@ -1409,7 +1412,7 @@ static int do_write(struct fsg_dev *fsg)
empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
fsg->short_packet_received = 1;
break;
}
@@ -1953,7 +1956,7 @@ static int throw_away_data(struct fsg_dev *fsg)
fsg->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
return -EINTR;
@@ -1971,9 +1974,7 @@ static int throw_away_data(struct fsg_dev *fsg)
* equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -2652,7 +2653,6 @@ static int get_next_command(struct fsg_dev *fsg)
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);