aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/f_mass_storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/f_mass_storage.c')
-rw-r--r--drivers/usb/gadget/f_mass_storage.c527
1 files changed, 508 insertions, 19 deletions
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 8826763..6a4f5e1 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -297,6 +297,11 @@
#include "gadget_chips.h"
+#ifdef CONFIG_USB_CDFS_SUPPORT
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+#define _SUPPORT_MAC_ /* support to recognize CDFS on OSX (MAC PC) */
+#endif
+#endif
/*------------------------------------------------------------------------*/
@@ -406,6 +411,11 @@ struct fsg_common {
*/
char inquiry_string[8 + 16 + 4 + 1];
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ char vendor_string[8 + 1];
+ char product_string[16 + 1];
+#endif
+
struct kref ref;
};
@@ -451,6 +461,62 @@ struct fsg_dev {
struct usb_ep *bulk_out;
};
+#ifdef CONFIG_USB_CDFS_SUPPORT
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+static int send_message(struct fsg_common *common, char *msg)
+{
+ char name_buf[120];
+ char state_buf[120];
+ char *envp[3];
+ int env_offset = 0;
+ struct usb_gadget *gadget = common->gadget;
+
+ DBG(common, "%s called\n", __func__);
+ printk(KERN_INFO "%s (%s)\n", __func__, msg);
+
+ if (gadget) {
+ snprintf(name_buf, sizeof(name_buf),
+ "SWITCH_NAME=USB_MESSAGE");
+ envp[env_offset++] = name_buf;
+
+ snprintf(state_buf, sizeof(state_buf),
+ "SWITCH_STATE=%s", msg);
+ envp[env_offset++] = state_buf;
+
+ envp[env_offset] = NULL;
+
+ if (!gadget->dev.class) {
+ gadget->dev.class = class_create(THIS_MODULE,
+ "usb_msg");
+ if (IS_ERR(gadget->dev.class))
+ return -1;
+ }
+
+ DBG(common, "Send cd eject message to daemon\n");
+
+ kobject_uevent_env(&gadget->dev.kobj, KOBJ_CHANGE, envp);
+ }
+
+ return 0;
+}
+
+static int do_autorun_check(struct fsg_common *common)
+{
+ printk(KERN_INFO "%s called\n", __func__);
+ send_message(common, "autorun");
+
+ return 0;
+}
+
+static int do_switch_atmode(struct fsg_common *common)
+{
+ printk(KERN_INFO "%s called\n", __func__);
+ send_message(common, "Load AT");
+
+ return 0;
+}
+#endif /* CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE */
+#endif
static inline int __fsg_is_set(struct fsg_common *common,
const char *func, unsigned line)
{
@@ -735,6 +801,243 @@ static int sleep_thread(struct fsg_common *common)
return rc;
}
+#ifdef CONFIG_USB_CDFS_SUPPORT
+#ifdef _SUPPORT_MAC_
+static void _lba_to_msf(u8 *buf, int lba)
+{
+ lba += 150;
+ buf[0] = (lba / 75) / 60;
+ buf[1] = (lba / 75) % 60;
+ buf[2] = lba % 75;
+}
+
+static int _read_toc_raw(struct fsg_common *common, struct fsg_buffhd *bh)
+{
+ struct fsg_lun *curlun = common->curlun;
+ int msf = common->cmnd[1] & 0x02;
+ u8 *buf = (u8 *) bh->buf;
+
+ u8 *q;
+ int len;
+
+ q = buf + 2;
+ *q++ = 1; /* first session */
+ *q++ = 1; /* last session */
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa0; /* lead-in */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ *q++ = 0;
+ *q++ = 1; /* first track */
+ *q++ = 0x00; /* disk type */
+ *q++ = 0x00;
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa1;
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ *q++ = 0;
+ *q++ = 1; /* last track */
+ *q++ = 0x00;
+ *q++ = 0x00;
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* data track */
+ *q++ = 0; /* track number */
+ *q++ = 0xa2; /* lead-out */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ if (msf) {
+ *q++ = 0; /* reserved */
+ _lba_to_msf(q, curlun->num_sectors);
+ q += 3;
+ } else {
+ put_unaligned_be32(curlun->num_sectors, q);
+ q += 4;
+ }
+
+ *q++ = 1; /* session number */
+ *q++ = 0x14; /* ADR, control */
+ *q++ = 0; /* track number */
+ *q++ = 1; /* point */
+ *q++ = 0; /* min */
+ *q++ = 0; /* sec */
+ *q++ = 0; /* frame */
+ if (msf) {
+ *q++ = 0;
+ _lba_to_msf(q, 0);
+ q += 3;
+ } else {
+ *q++ = 0;
+ *q++ = 0;
+ *q++ = 0;
+ *q++ = 0;
+ }
+
+ len = q - buf;
+ put_unaligned_be16(len - 2, buf);
+
+ return len;
+}
+
+static void cd_data_to_raw(u8 *buf, int lba)
+{
+ /* sync bytes */
+ buf[0] = 0x00;
+ memset(buf + 1, 0xff, 10);
+ buf[11] = 0x00;
+ buf += 12;
+ /* MSF */
+ _lba_to_msf(buf, lba);
+ buf[3] = 0x01; /* mode 1 data */
+ buf += 4;
+ /* data */
+ buf += 2048;
+ /* XXX: ECC not computed */
+ memset(buf, 0, 288);
+}
+
+static int do_read_cd(struct fsg_common *common)
+{
+ struct fsg_lun *curlun = common->curlun;
+ u32 lba;
+ struct fsg_buffhd *bh;
+ int rc;
+ u32 amount_left;
+ loff_t file_offset, file_offset_tmp;
+ unsigned int amount;
+ unsigned int partial_page;
+ ssize_t nread;
+
+ u32 nb_sectors, transfer_request;
+
+ nb_sectors = (common->cmnd[6] << 16) |
+ (common->cmnd[7] << 8) | common->cmnd[8];
+ lba = get_unaligned_be32(&common->cmnd[2]);
+
+ if (nb_sectors == 0)
+ return 0;
+
+ if (lba >= curlun->num_sectors) {
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ transfer_request = common->cmnd[9];
+ if ((transfer_request & 0xf8) == 0xf8) {
+ file_offset = ((loff_t) lba) << 11;
+ /* read all data - 2352 byte */
+ amount_left = 2352;
+ } else {
+ file_offset = ((loff_t) lba) << 9;
+ /* Carry out the file reads */
+ amount_left = common->data_size_from_cmnd;
+ }
+
+ if (unlikely(amount_left == 0))
+ return -EIO; /* No default reply */
+
+ for (;;) {
+
+ /* Figure out how much we need to read:
+ * 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;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+
+ /* If we were asked to read past the end of file,
+ * end with an empty buffer. */
+ if (amount == 0) {
+ curlun->sense_data =
+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
+ bh->inreq->length = 0;
+ bh->state = BUF_STATE_FULL;
+ break;
+ }
+
+ /* Perform the read */
+ file_offset_tmp = file_offset;
+ if ((transfer_request & 0xf8) == 0xf8) {
+ nread = vfs_read(curlun->filp,
+ ((char __user *)bh->buf)+16,
+ amount, &file_offset_tmp);
+ } else {
+ nread = vfs_read(curlun->filp,
+ (char __user *)bh->buf,
+ amount, &file_offset_tmp);
+ }
+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+ (unsigned long long) file_offset,
+ (int) nread);
+ if (signal_pending(current))
+ return -EINTR;
+
+ if (nread < 0) {
+ LDBG(curlun, "error in file read: %d\n",
+ (int) nread);
+ nread = 0;
+ } else if (nread < amount) {
+ LDBG(curlun, "partial file read: %d/%u\n",
+ (int) nread, amount);
+ nread -= (nread & 511); /* Round down to a block */
+ }
+ file_offset += nread;
+ amount_left -= nread;
+ common->residue -= nread;
+ 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->info_valid = 1;
+ break;
+ }
+
+ if (amount_left == 0)
+ break; /* No more left to read */
+
+ /* Send this buffer and go read some more */
+ start_in_transfer(common, bh);
+ common->next_buffhd_to_fill = bh->next;
+ }
+
+ if ((transfer_request & 0xf8) == 0xf8)
+ cd_data_to_raw(bh->buf, lba);
+
+ return -EIO; /* No default reply */
+}
+#endif /* _SUPPORT_MAC_ */
+#endif
/*-------------------------------------------------------------------------*/
@@ -773,12 +1076,27 @@ 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;
- if (unlikely(amount_left == 0))
+ if (unlikely(amount_left == 0)) {
+ /* Wait for the next buffer to become available */
+ bh = common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(common);
+ if (rc)
+ return rc;
+ }
+ bh->inreq->length = 0;
return -EIO; /* No default reply */
+ }
+ if (curlun->cdrom)
+ amount_left <<= 2;
for (;;) {
/*
@@ -795,9 +1113,22 @@ static int do_read(struct fsg_common *common)
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);
+ if (common->gadget->speed != USB_SPEED_SUPER) {
+ if (partial_page > 0)
+ amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
+ partial_page);
+ }
+
+ if (common->gadget->speed == USB_SPEED_SUPER) {
+ /* The packet should be multiple of MPS, which is 1024. */
+ if (amount < amount_left) {
+ unsigned mod = amount % common->bulk_out_maxpacket;
+ if (mod && (amount - mod)) {
+ // not a multiple of maxpacket
+ amount -= mod;
+ }
+ }
+ }
/* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill;
@@ -878,7 +1209,7 @@ static int do_write(struct fsg_common *common)
int get_some_more;
u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp;
- unsigned int amount;
+ unsigned int amount, diff;
unsigned int partial_page;
ssize_t nwritten;
int rc;
@@ -948,9 +1279,12 @@ static int do_write(struct fsg_common *common)
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 (common->gadget->speed != USB_SPEED_SUPER) {
+ if (partial_page > 0)
+ amount = min(amount,
+ (unsigned int) PAGE_CACHE_SIZE -
+ partial_page);
+ }
if (amount == 0) {
get_some_more = 0;
@@ -971,6 +1305,17 @@ static int do_write(struct fsg_common *common)
continue;
}
+ if (common->gadget->speed == USB_SPEED_SUPER) {
+ /* The packet should be multiple of MPS, which is 1024. */
+ if (amount < amount_left_to_write) {
+ unsigned mod = amount % common->bulk_out_maxpacket;
+ if (mod && (amount - mod)) {
+ // not a multiple of maxpacket
+ amount -= mod;
+ }
+ }
+ }
+
/* Get the next buffer */
usb_offset += amount;
common->usb_amount_left -= amount;
@@ -1010,6 +1355,12 @@ static int do_write(struct fsg_common *common)
}
amount = bh->outreq->actual;
+ if (amount > bh->outreq->length) {
+ diff = amount - bh->outreq->length;
+ amount = bh->outreq->length;
+ } else {
+ diff = 0;
+ }
if (curlun->file_length - file_offset < amount) {
LERROR(curlun,
"write %u @ %llu beyond end %llu\n",
@@ -1042,6 +1393,15 @@ static int do_write(struct fsg_common *common)
amount_left_to_write -= nwritten;
common->residue -= nwritten;
+ if (diff) {
+ LDBG(curlun, "host sent too much data: %d\n", diff);
+ LDBG(curlun, "data_size=%d residue=%d amt_left=%d\n",
+ common->data_size, common->residue, common->usb_amount_left);
+ common->data_size = common->residue;
+ common->usb_amount_left = 0;
+ break;
+ }
+
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
@@ -1202,6 +1562,9 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
{
struct fsg_lun *curlun = common->curlun;
u8 *buf = (u8 *) bh->buf;
+#if defined(CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE)
+ static char new_product_name[16 + 1];
+#endif
if (!curlun) { /* Unsupported LUNs are okay */
common->bad_lun_okay = 1;
@@ -1219,6 +1582,23 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
buf[5] = 0; /* No special options */
buf[6] = 0;
buf[7] = 0;
+
+#if defined(CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE)
+ strncpy(new_product_name, common->product_string, 16);
+ new_product_name[16] = '\0';
+ if (common->product_string[0] &&
+ strlen(common->product_string) <= 11 && /* check string length */
+ common->lun > 0) {
+ strncat(new_product_name, " Card", 16);
+ new_product_name[16] = '\0';
+ }
+
+ snprintf(common->inquiry_string,
+ sizeof common->inquiry_string,
+ "%-8s%-16s%04x",
+ common->vendor_string,
+ new_product_name, 1);
+#endif
memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
return 36;
}
@@ -1291,7 +1671,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;
}
@@ -1323,13 +1703,22 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
int msf = common->cmnd[1] & 0x02;
int start_track = common->cmnd[6];
u8 *buf = (u8 *)bh->buf;
-
+#if defined(CONFIG_USB_CDFS_SUPPORT)
+#ifdef _SUPPORT_MAC_
+ int format = (common->cmnd[9] & 0xC0) >> 6;
+#endif
+#endif
if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
start_track > 1) {
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
}
-
+#if defined(CONFIG_USB_CDFS_SUPPORT)
+#ifdef _SUPPORT_MAC_
+ if (format == 2)
+ return _read_toc_raw(common, bh);
+#endif
+#endif
memset(buf, 0, 20);
buf[1] = (20-2); /* TOC data length */
buf[2] = 1; /* First track number */
@@ -1454,6 +1843,12 @@ static int do_start_stop(struct fsg_common *common)
* available for use as soon as it is loaded.
*/
if (start) {
+#if defined(CONFIG_USB_CDFS_SUPPORT)
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ if (loej)
+ send_message(common, "Load AT");
+#endif
+#endif
if (!fsg_lun_is_open(curlun)) {
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
return -EINVAL;
@@ -1487,6 +1882,12 @@ static int do_start_stop(struct fsg_common *common)
up_write(&common->filesem);
down_read(&common->filesem);
+#if defined(CONFIG_USB_CDFS_SUPPORT)
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ send_message(common, "Load User");
+#endif
+#endif
+
return common->ops && common->ops->post_eject
? min(0, common->ops->post_eject(common, curlun,
curlun - common->luns))
@@ -1529,7 +1930,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;
}
@@ -2079,7 +2480,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,
- (7<<6) | (1<<1), 1,
+ (0xf<<6) | (1<<1), 1,
"READ TOC");
if (reply == 0)
reply = do_read_toc(common, bh);
@@ -2172,15 +2573,43 @@ static int do_scsi_command(struct fsg_common *common)
reply = do_write(common);
break;
- /*
- * Some mandatory commands that we recognize but don't implement.
+#if defined(CONFIG_USB_CDFS_SUPPORT)
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ case RELEASE: /* SC_AUTORUN_CHECK0 : 0x17 */
+ reply = do_switch_atmode(common);
+ break;
+
+ case RESERVE: /* SC_AUTORUN_CHECK1 : 0x16 */
+ reply = do_autorun_check(common);
+ break;
+
+#ifdef _SUPPORT_MAC_
+ case READ_CD:
+ common->data_size_from_cmnd = ((common->cmnd[6] << 16)
+ | (common->cmnd[7] << 8)
+ | (common->cmnd[8])) << 9;
+ reply = check_command(common, 12, DATA_DIR_TO_HOST,
+ (0xf<<2) | (7<<7), 1,
+ "READ CD");
+ if (reply == 0)
+ reply = do_read_cd(common);
+ break;
+
+#endif /* _SUPPORT_MAC_ */
+#endif
+#endif
+ /* Some mandatory commands that we recognize but don't implement.
* They don't mean much in this setting. It's left as an exercise
* for anyone interested to implement RESERVE and RELEASE in terms
* of Posix locks.
*/
case FORMAT_UNIT:
+#ifndef CONFIG_USB_CDFS_SUPPORT
+#ifndef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
case RELEASE:
case RESERVE:
+#endif
+#endif
case SEND_DIAGNOSTIC:
/* Fall through */
@@ -2332,6 +2761,17 @@ static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
int rc;
ep->driver_data = common;
+
+ if (common->gadget->speed == USB_SPEED_SUPER) {
+ if (ep == common->fsg->bulk_in)
+ ep->maxburst = fsg_ss_bulk_in_comp_desc.bMaxBurst;
+ else if (ep == common->fsg->bulk_out)
+ ep->maxburst = fsg_ss_bulk_out_comp_desc.bMaxBurst;
+ else
+ ep->maxburst = 0;
+ } else
+ ep->maxburst = 0;
+
rc = usb_ep_enable(ep, d);
if (rc)
ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
@@ -2398,14 +2838,22 @@ reset:
fsg = common->fsg;
/* Enable the endpoints */
- d = fsg_ep_desc(common->gadget,
+ if (gadget_is_superspeed(common->gadget) &&
+ common->gadget->speed == USB_SPEED_SUPER)
+ d = &fsg_ss_bulk_in_desc;
+ else
+ d = fsg_ep_desc(common->gadget,
&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
rc = enable_endpoint(common, fsg->bulk_in, d);
if (rc)
goto reset;
fsg->bulk_in_enabled = 1;
- d = fsg_ep_desc(common->gadget,
+ if (gadget_is_superspeed(common->gadget) &&
+ common->gadget->speed == USB_SPEED_SUPER)
+ d = &fsg_ss_bulk_out_desc;
+ else
+ d = fsg_ep_desc(common->gadget,
&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
rc = enable_endpoint(common, fsg->bulk_out, d);
if (rc)
@@ -2696,6 +3144,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 ******************************/
@@ -2781,6 +3230,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
curlun->ro = lcfg->cdrom || lcfg->ro;
curlun->initially_ro = curlun->ro;
curlun->removable = lcfg->removable;
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ curlun->nofua = lcfg->nofua;
+#endif
curlun->dev.release = fsg_lun_release;
curlun->dev.parent = &gadget->dev;
/* curlun->dev.driver = &fsg_driver.driver; XXX */
@@ -2808,6 +3260,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
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;
+
if (lcfg->filename) {
rc = fsg_lun_open(curlun, lcfg->filename);
@@ -2858,6 +3314,15 @@ buffhds_first_it:
: "File-CD Gadget"),
i);
+#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
+ /* Default INQUIRY strings */
+ strncpy(common->vendor_string, "SAMSUNG",
+ sizeof(common->vendor_string) - 1);
+ strncpy(common->product_string, "File-Stor Gadget",
+ sizeof(common->product_string) - 1);
+ common->product_string[sizeof(common->product_string) - 1] = '\0';
+#endif
+
/*
* Some peripheral controllers are known not to be able to
* halt bulk endpoints correctly. If one of them is present,
@@ -2940,6 +3405,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);
}
@@ -2978,6 +3444,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
fsg_common_put(common);
usb_free_descriptors(fsg->function.descriptors);
usb_free_descriptors(fsg->function.hs_descriptors);
+ usb_free_descriptors(fsg->function.ss_descriptors);
kfree(fsg);
}
@@ -3028,6 +3495,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:
@@ -3054,7 +3543,7 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
if (unlikely(!fsg))
return -ENOMEM;
- fsg->function.name = FSG_DRIVER_DESC;
+ fsg->function.name = "mass_storage";
fsg->function.strings = fsg_strings_array;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;