diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-01-09 11:38:23 +0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-01-09 11:38:23 +0400 |
commit | da733563be5a9da26fe81d9f007262d00b846e22 (patch) | |
tree | db28291df94a2043af2123911984c5c173da4e6f /drivers/usb/gadget/f_mass_storage.c | |
parent | 6ccbcf2cb41131f8d56ef0723bf3f7c1f8486076 (diff) | |
parent | dab78d7924598ea4031663dd10db814e2e324928 (diff) | |
download | linux-da733563be5a9da26fe81d9f007262d00b846e22.tar.xz |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/usb/gadget/f_mass_storage.c')
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 202 |
1 files changed, 115 insertions, 87 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5b9339582007..c39d58860fa0 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 @@ -363,7 +362,7 @@ struct fsg_common { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; + struct fsg_buffhd *buffhds; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -625,7 +624,8 @@ static int fsg_setup(struct usb_function *f, if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != fsg->interface_number || w_value != 0) + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 0) return -EDOM; /* @@ -640,7 +640,8 @@ static int fsg_setup(struct usb_function *f, if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != fsg->interface_number || w_value != 0) + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 1) return -EDOM; VDBG(fsg, "get max LUN\n"); *(u8 *)req->buf = fsg->common->nluns - 1; @@ -745,7 +746,6 @@ static int do_read(struct fsg_common *common) u32 amount_left; loff_t file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nread; /* @@ -771,7 +771,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; @@ -784,18 +784,10 @@ static int do_read(struct fsg_common *common) * Try to read the remaining amount. * But don't read more than the buffer size. * 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(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, 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 */ bh = common->next_buffhd_to_fill; @@ -812,7 +804,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,18 +828,25 @@ 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; common->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->state = BUF_STATE_FULL; /* 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; } @@ -877,7 +877,6 @@ static int do_write(struct fsg_common *common) u32 amount_left_to_req, amount_left_to_write; loff_t usb_offset, file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nwritten; int rc; @@ -921,7 +920,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; @@ -933,41 +932,21 @@ static int do_write(struct fsg_common *common) /* * 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, FSG_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; 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; - if (amount == 0) { - - /* - * Why were we were asked to transfer a - * partial block? - */ - get_some_more = 0; - continue; - } /* Get the next buffer */ usb_offset += amount; @@ -977,12 +956,11 @@ static int do_write(struct fsg_common *common) 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 = 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; @@ -1002,7 +980,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; } @@ -1016,6 +995,16 @@ 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) + goto empty_write; + /* Perform the write */ file_offset_tmp = file_offset; nwritten = vfs_write(curlun->filp, @@ -1033,8 +1022,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,13 +1031,15 @@ 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; } + 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; } @@ -1129,8 +1119,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); @@ -1148,8 +1138,6 @@ static int do_verify(struct fsg_common *common) * Try to read the remaining amount, but not more than * the buffer size. * 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(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, @@ -1157,7 +1145,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 +1168,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 +1279,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 +1517,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; } @@ -1607,7 +1597,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); @@ -1623,12 +1613,11 @@ static int throw_away_data(struct fsg_common *common) amount = min(common->usb_amount_left, FSG_BUFLEN); /* - * amount is always divisible by 512, hence by + * 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 = 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; @@ -2022,7 +2011,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 +2022,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 +2033,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 +2134,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 +2145,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 +2156,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)"); @@ -2297,7 +2292,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; @@ -2348,7 +2342,7 @@ reset: if (common->fsg) { fsg = common->fsg; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; if (bh->inreq) { @@ -2401,12 +2395,11 @@ reset: goto reset; fsg->bulk_out->driver_data = common; fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = - le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize); + common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2475,7 +2468,7 @@ static void handle_exception(struct fsg_common *common) /* Cancel all the pending transfers */ if (likely(common->fsg)) { - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2487,7 +2480,7 @@ static void handle_exception(struct fsg_common *common) /* Wait until everything is idle */ for (;;) { int num_active = 0; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2510,7 +2503,7 @@ static void handle_exception(struct fsg_common *common) */ spin_lock_irq(&common->lock); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -2719,6 +2712,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, int nluns, i, rc; char *pathbuf; + rc = fsg_num_buffers_validate(); + if (rc != 0) + return ERR_PTR(rc); + /* Find out how many LUNs there should be */ nluns = cfg->nluns; if (nluns < 1 || nluns > FSG_MAX_LUNS) { @@ -2737,6 +2734,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, common->free_storage_on_release = 0; } + common->buffhds = kcalloc(fsg_num_buffers, + sizeof *(common->buffhds), GFP_KERNEL); + if (!common->buffhds) { + if (common->free_storage_on_release) + kfree(common); + return ERR_PTR(-ENOMEM); + } + common->ops = cfg->ops; common->private_data = cfg->private_data; @@ -2814,7 +2819,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, /* Data buffers cyclic list */ bh = common->buffhds; - i = FSG_NUM_BUFFERS; + i = fsg_num_buffers; goto buffhds_first_it; do { bh->next = bh + 1; @@ -2940,12 +2945,13 @@ static void fsg_common_release(struct kref *ref) { struct fsg_buffhd *bh = common->buffhds; - unsigned i = FSG_NUM_BUFFERS; + unsigned i = fsg_num_buffers; do { kfree(bh->buf); } while (++bh, --i); } + kfree(common->buffhds); if (common->free_storage_on_release) kfree(common); } @@ -3019,6 +3025,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) } } + if (gadget_is_superspeed(gadget)) { + unsigned max_burst; + + /* Calculate bMaxBurst, we know packet size is 1024 */ + max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); + + fsg_ss_bulk_in_desc.bEndpointAddress = + fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; + + fsg_ss_bulk_out_desc.bEndpointAddress = + fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; + + f->ss_descriptors = usb_copy_descriptors(fsg_ss_function); + if (unlikely(!f->ss_descriptors)) { + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->descriptors); + return -ENOMEM; + } + } + return 0; autoconf_fail: |