diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index b8940dc20a02..4ebb9a7ee6cc 100755 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -1096,7 +1096,10 @@ 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; + if (curlun->cdrom) + file_offset = ((loff_t) lba) << 11; + else + file_offset = ((loff_t) lba) << 9; /* Carry out the file reads */ amount_left = common->data_size_from_cmnd; @@ -1111,6 +1114,8 @@ static int do_read(struct fsg_common *common) bh->inreq->length = 0; return -EIO; /* No default reply */ } + if (curlun->cdrom) + amount_left <<= 2; for (;;) { /* @@ -1685,7 +1690,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->cdrom ? 2048 : 512, &buf[4]); /* Block length */ return 8; } @@ -1961,7 +1966,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->cdrom ? 2048 : 512, &buf[4]); /* Block length */ buf[4] = 0x02; /* Current capacity */ return 12; } @@ -2354,7 +2359,9 @@ static int check_command(struct fsg_common *common, int cmnd_size, return -EINVAL; } - /* Check that only command bytes listed in the mask are non-zero */ + /* Check that only command bytes listed in the mask are non-zero + * Some BIOSes put some non-zero values in READ_TOC requests in + * the last two bytes */ common->cmnd[1] &= 0x1f; /* Mask away the LUN */ for (i = 1; i < cmnd_size; ++i) { if (common->cmnd[i] && !(mask & (1 << i))) { @@ -2511,16 +2518,7 @@ static int do_scsi_command(struct fsg_common *common) common->data_size_from_cmnd = get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, -#if defined(CONFIG_USB_CDFS_SUPPORT) -#ifdef _SUPPORT_MAC_ (0xf<<6) | (1<<1), 1, -#else - (7<<6) | (1<<1), 1, -#endif -#else - (7<<6) | (1<<1), 1, -#endif - "READ TOC"); if (reply == 0) reply = do_read_toc(common, bh); @@ -3190,6 +3188,7 @@ static int fsg_main_thread(void *common_) static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); +static DEVICE_ATTR(cdrom, 0644, fsg_show_cdrom, fsg_store_cdrom); /****************************** FSG COMMON ******************************/ @@ -3303,6 +3302,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, if (rc) goto error_luns; rc = device_create_file(&curlun->dev, &dev_attr_nofua); + if (rc) + goto error_luns; + rc = device_create_file(&curlun->dev, &dev_attr_cdrom); if (rc) goto error_luns; @@ -3446,6 +3448,7 @@ static void fsg_common_release(struct kref *ref) device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, &dev_attr_ro); device_remove_file(&lun->dev, &dev_attr_file); + device_remove_file(&lun->dev, &dev_attr_cdrom); fsg_lun_close(lun); device_unregister(&lun->dev); } diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 70a474c5266b..19070fa06ada 100755 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -701,10 +701,10 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) num_sectors = size >> 9; /* File size in 512-byte 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; + num_sectors >>= 2; /* Reduce to a multiple of 2048 */ + 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); @@ -759,7 +759,6 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr) { if (msf) { /* Convert to Minutes-Seconds-Frames */ - addr >>= 2; /* Convert to 2048-byte frames */ addr += 2*75; /* Lead-in occupies 2 seconds */ dest[3] = addr % 75; /* Frames */ addr /= 75; @@ -913,3 +912,40 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, up_write(filesem); return (rc < 0 ? rc : count); } + +static ssize_t fsg_show_cdrom (struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%u\n", curlun->cdrom); +} + +static ssize_t fsg_store_cdrom(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t rc; + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + unsigned cdrom; + + rc = kstrtouint(buf, 2, &cdrom); + if (rc) + return rc; + + /* + * Allow the cdrom status to change only while the + * backing file is closed. + */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "cdrom status change prevented\n"); + rc = -EBUSY; + } else { + curlun->cdrom = !!cdrom; + LDBG(curlun, "cdrom status set to %d\n", curlun->cdrom); + rc = count; + } + up_read(filesem); + return rc; +}