|
@@ -1,7 +1,7 @@
|
|
/*
|
|
/*
|
|
* file_storage.c -- File-backed USB Storage Gadget, for USB development
|
|
* file_storage.c -- File-backed USB Storage Gadget, for USB development
|
|
*
|
|
*
|
|
- * Copyright (C) 2003-2007 Alan Stern
|
|
|
|
|
|
+ * Copyright (C) 2003-2008 Alan Stern
|
|
* All rights reserved.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -38,16 +38,17 @@
|
|
|
|
|
|
/*
|
|
/*
|
|
* The File-backed Storage Gadget acts as a USB Mass Storage device,
|
|
* The File-backed Storage Gadget acts as a USB Mass Storage device,
|
|
- * appearing to the host as a disk drive. In addition to providing an
|
|
|
|
- * example of a genuinely useful gadget driver for a USB device, it also
|
|
|
|
- * illustrates a technique of double-buffering for increased throughput.
|
|
|
|
- * Last but not least, it gives an easy way to probe the behavior of the
|
|
|
|
- * Mass Storage drivers in a USB host.
|
|
|
|
|
|
+ * appearing to the host as a disk drive or as a CD-ROM drive. In addition
|
|
|
|
+ * to providing an example of a genuinely useful gadget driver for a USB
|
|
|
|
+ * device, it also illustrates a technique of double-buffering for increased
|
|
|
|
+ * throughput. Last but not least, it gives an easy way to probe the
|
|
|
|
+ * behavior of the Mass Storage drivers in a USB host.
|
|
*
|
|
*
|
|
* Backing storage is provided by a regular file or a block device, specified
|
|
* Backing storage is provided by a regular file or a block device, specified
|
|
* by the "file" module parameter. Access can be limited to read-only by
|
|
* by the "file" module parameter. Access can be limited to read-only by
|
|
- * setting the optional "ro" module parameter. The gadget will indicate that
|
|
|
|
- * it has removable media if the optional "removable" module parameter is set.
|
|
|
|
|
|
+ * setting the optional "ro" module parameter. (For CD-ROM emulation,
|
|
|
|
+ * access is always read-only.) The gadget will indicate that it has
|
|
|
|
+ * removable media if the optional "removable" module parameter is set.
|
|
*
|
|
*
|
|
* The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
|
|
* The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
|
|
* and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
|
|
* and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
|
|
@@ -64,7 +65,12 @@
|
|
* The default number of LUNs is taken from the number of "file" elements;
|
|
* The default number of LUNs is taken from the number of "file" elements;
|
|
* it is 1 if "file" is not given. If "removable" is not set then a backing
|
|
* it is 1 if "file" is not given. If "removable" is not set then a backing
|
|
* file must be specified for each LUN. If it is set, then an unspecified
|
|
* file must be specified for each LUN. If it is set, then an unspecified
|
|
- * or empty backing filename means the LUN's medium is not loaded.
|
|
|
|
|
|
+ * or empty backing filename means the LUN's medium is not loaded. Ideally
|
|
|
|
+ * 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
|
|
|
|
+ * 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.
|
|
*
|
|
*
|
|
* 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
|
|
@@ -91,6 +97,8 @@
|
|
* USB device controller (usually true),
|
|
* USB device controller (usually true),
|
|
* boolean to permit the driver to halt
|
|
* boolean to permit the driver to halt
|
|
* bulk endpoints
|
|
* bulk endpoints
|
|
|
|
+ * cdrom Default false, boolean for whether to emulate
|
|
|
|
+ * a CD-ROM drive
|
|
* transport=XXX Default BBB, transport name (CB, CBI, or BBB)
|
|
* transport=XXX Default BBB, transport name (CB, CBI, or BBB)
|
|
* protocol=YYY Default SCSI, protocol name (RBC, 8020 or
|
|
* protocol=YYY Default SCSI, protocol name (RBC, 8020 or
|
|
* ATAPI, QIC, UFI, 8070, or SCSI;
|
|
* ATAPI, QIC, UFI, 8070, or SCSI;
|
|
@@ -103,15 +111,16 @@
|
|
* PAGE_CACHE_SIZE)
|
|
* PAGE_CACHE_SIZE)
|
|
*
|
|
*
|
|
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
|
|
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
|
|
- * "removable", "luns", and "stall" options are available; default values
|
|
|
|
- * are used for everything else.
|
|
|
|
|
|
+ * "removable", "luns", "stall", and "cdrom" options are available; default
|
|
|
|
+ * values are used for everything else.
|
|
*
|
|
*
|
|
* The pathnames of the backing files and the ro settings are available in
|
|
* The pathnames of the backing files and the ro settings are available in
|
|
* the attribute files "file" and "ro" in the lun<n> subdirectory of the
|
|
* the attribute files "file" and "ro" in the lun<n> subdirectory of the
|
|
* gadget's sysfs directory. If the "removable" option is set, writing to
|
|
* gadget's sysfs directory. If the "removable" option is set, writing to
|
|
* these files will simulate ejecting/loading the medium (writing an empty
|
|
* these files will simulate ejecting/loading the medium (writing an empty
|
|
* line means eject) and adjusting a write-enable tab. Changes to the ro
|
|
* line means eject) and adjusting a write-enable tab. Changes to the ro
|
|
- * setting are not allowed when the medium is loaded.
|
|
|
|
|
|
+ * setting are not allowed when the medium is loaded or if CD-ROM emulation
|
|
|
|
+ * is being used.
|
|
*
|
|
*
|
|
* This gadget driver is heavily based on "Gadget Zero" by David Brownell.
|
|
* This gadget driver is heavily based on "Gadget Zero" by David Brownell.
|
|
* The driver's SCSI command interface was based on the "Information
|
|
* The driver's SCSI command interface was based on the "Information
|
|
@@ -261,7 +270,7 @@
|
|
|
|
|
|
#define DRIVER_DESC "File-backed Storage Gadget"
|
|
#define DRIVER_DESC "File-backed Storage Gadget"
|
|
#define DRIVER_NAME "g_file_storage"
|
|
#define DRIVER_NAME "g_file_storage"
|
|
-#define DRIVER_VERSION "7 August 2007"
|
|
|
|
|
|
+#define DRIVER_VERSION "20 November 2008"
|
|
|
|
|
|
static const char longname[] = DRIVER_DESC;
|
|
static const char longname[] = DRIVER_DESC;
|
|
static const char shortname[] = DRIVER_NAME;
|
|
static const char shortname[] = DRIVER_NAME;
|
|
@@ -341,6 +350,7 @@ static struct {
|
|
|
|
|
|
int removable;
|
|
int removable;
|
|
int can_stall;
|
|
int can_stall;
|
|
|
|
+ int cdrom;
|
|
|
|
|
|
char *transport_parm;
|
|
char *transport_parm;
|
|
char *protocol_parm;
|
|
char *protocol_parm;
|
|
@@ -359,6 +369,7 @@ static struct {
|
|
.protocol_parm = "SCSI",
|
|
.protocol_parm = "SCSI",
|
|
.removable = 0,
|
|
.removable = 0,
|
|
.can_stall = 1,
|
|
.can_stall = 1,
|
|
|
|
+ .cdrom = 0,
|
|
.vendor = DRIVER_VENDOR_ID,
|
|
.vendor = DRIVER_VENDOR_ID,
|
|
.product = DRIVER_PRODUCT_ID,
|
|
.product = DRIVER_PRODUCT_ID,
|
|
.release = 0xffff, // Use controller chip type
|
|
.release = 0xffff, // Use controller chip type
|
|
@@ -382,6 +393,9 @@ MODULE_PARM_DESC(removable, "true to simulate removable media");
|
|
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
|
|
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
|
|
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
|
|
|
|
|
|
|
|
+module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
|
|
|
|
+MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
|
|
|
|
+
|
|
|
|
|
|
/* In the non-TEST version, only the module parameters listed above
|
|
/* In the non-TEST version, only the module parameters listed above
|
|
* are available. */
|
|
* are available. */
|
|
@@ -411,6 +425,10 @@ MODULE_PARM_DESC(buflen, "I/O buffer size");
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
+/* SCSI device types */
|
|
|
|
+#define TYPE_DISK 0x00
|
|
|
|
+#define TYPE_CDROM 0x05
|
|
|
|
+
|
|
/* USB protocol value = the transport method */
|
|
/* USB protocol value = the transport method */
|
|
#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt
|
|
#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt
|
|
#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt
|
|
#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt
|
|
@@ -487,6 +505,8 @@ struct interrupt_data {
|
|
#define SC_READ_12 0xa8
|
|
#define SC_READ_12 0xa8
|
|
#define SC_READ_CAPACITY 0x25
|
|
#define SC_READ_CAPACITY 0x25
|
|
#define SC_READ_FORMAT_CAPACITIES 0x23
|
|
#define SC_READ_FORMAT_CAPACITIES 0x23
|
|
|
|
+#define SC_READ_HEADER 0x44
|
|
|
|
+#define SC_READ_TOC 0x43
|
|
#define SC_RELEASE 0x17
|
|
#define SC_RELEASE 0x17
|
|
#define SC_REQUEST_SENSE 0x03
|
|
#define SC_REQUEST_SENSE 0x03
|
|
#define SC_RESERVE 0x16
|
|
#define SC_RESERVE 0x16
|
|
@@ -2006,23 +2026,28 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
u8 *buf = (u8 *) bh->buf;
|
|
u8 *buf = (u8 *) bh->buf;
|
|
|
|
|
|
static char vendor_id[] = "Linux ";
|
|
static char vendor_id[] = "Linux ";
|
|
- static char product_id[] = "File-Stor Gadget";
|
|
|
|
|
|
+ static char product_disk_id[] = "File-Stor Gadget";
|
|
|
|
+ static char product_cdrom_id[] = "File-CD Gadget ";
|
|
|
|
|
|
if (!fsg->curlun) { // Unsupported LUNs are okay
|
|
if (!fsg->curlun) { // Unsupported LUNs are okay
|
|
fsg->bad_lun_okay = 1;
|
|
fsg->bad_lun_okay = 1;
|
|
memset(buf, 0, 36);
|
|
memset(buf, 0, 36);
|
|
buf[0] = 0x7f; // Unsupported, no device-type
|
|
buf[0] = 0x7f; // Unsupported, no device-type
|
|
|
|
+ buf[4] = 31; // Additional length
|
|
return 36;
|
|
return 36;
|
|
}
|
|
}
|
|
|
|
|
|
- memset(buf, 0, 8); // Non-removable, direct-access device
|
|
|
|
|
|
+ memset(buf, 0, 8);
|
|
|
|
+ buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
|
|
if (mod_data.removable)
|
|
if (mod_data.removable)
|
|
buf[1] = 0x80;
|
|
buf[1] = 0x80;
|
|
buf[2] = 2; // ANSI SCSI level 2
|
|
buf[2] = 2; // ANSI SCSI level 2
|
|
buf[3] = 2; // SCSI-2 INQUIRY data format
|
|
buf[3] = 2; // SCSI-2 INQUIRY data format
|
|
buf[4] = 31; // Additional length
|
|
buf[4] = 31; // Additional length
|
|
// No special options
|
|
// No special options
|
|
- sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,
|
|
|
|
|
|
+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
|
|
|
|
+ (mod_data.cdrom ? product_cdrom_id :
|
|
|
|
+ product_disk_id),
|
|
mod_data.release);
|
|
mod_data.release);
|
|
return 36;
|
|
return 36;
|
|
}
|
|
}
|
|
@@ -2101,6 +2126,75 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+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;
|
|
|
|
+ dest[2] = addr % 60; /* Seconds */
|
|
|
|
+ addr /= 60;
|
|
|
|
+ dest[1] = addr; /* Minutes */
|
|
|
|
+ dest[0] = 0; /* Reserved */
|
|
|
|
+ } else {
|
|
|
|
+ /* Absolute sector */
|
|
|
|
+ put_be32(dest, addr);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
|
|
+{
|
|
|
|
+ struct lun *curlun = fsg->curlun;
|
|
|
|
+ int msf = fsg->cmnd[1] & 0x02;
|
|
|
|
+ u32 lba = get_be32(&fsg->cmnd[2]);
|
|
|
|
+ u8 *buf = (u8 *) bh->buf;
|
|
|
|
+
|
|
|
|
+ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
|
|
|
|
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ if (lba >= curlun->num_sectors) {
|
|
|
|
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memset(buf, 0, 8);
|
|
|
|
+ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
|
|
|
|
+ store_cdrom_address(&buf[4], msf, lba);
|
|
|
|
+ return 8;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
|
|
+{
|
|
|
|
+ struct lun *curlun = fsg->curlun;
|
|
|
|
+ int msf = fsg->cmnd[1] & 0x02;
|
|
|
|
+ int start_track = fsg->cmnd[6];
|
|
|
|
+ u8 *buf = (u8 *) bh->buf;
|
|
|
|
+
|
|
|
|
+ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
|
|
|
|
+ start_track > 1) {
|
|
|
|
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memset(buf, 0, 20);
|
|
|
|
+ buf[1] = (20-2); /* TOC data length */
|
|
|
|
+ buf[2] = 1; /* First track number */
|
|
|
|
+ buf[3] = 1; /* Last track number */
|
|
|
|
+ buf[5] = 0x16; /* Data track, copying allowed */
|
|
|
|
+ buf[6] = 0x01; /* Only track is number 1 */
|
|
|
|
+ store_cdrom_address(&buf[8], msf, 0);
|
|
|
|
+
|
|
|
|
+ buf[13] = 0x16; /* Lead-out track is data */
|
|
|
|
+ buf[14] = 0xAA; /* Lead-out track number */
|
|
|
|
+ store_cdrom_address(&buf[16], msf, curlun->num_sectors);
|
|
|
|
+ return 20;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|
{
|
|
{
|
|
struct lun *curlun = fsg->curlun;
|
|
struct lun *curlun = fsg->curlun;
|
|
@@ -2848,6 +2942,26 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
reply = do_read_capacity(fsg, bh);
|
|
reply = do_read_capacity(fsg, bh);
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case SC_READ_HEADER:
|
|
|
|
+ if (!mod_data.cdrom)
|
|
|
|
+ goto unknown_cmnd;
|
|
|
|
+ fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
|
|
|
|
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
|
|
|
+ (3<<7) | (0x1f<<1), 1,
|
|
|
|
+ "READ HEADER")) == 0)
|
|
|
|
+ reply = do_read_header(fsg, bh);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SC_READ_TOC:
|
|
|
|
+ if (!mod_data.cdrom)
|
|
|
|
+ goto unknown_cmnd;
|
|
|
|
+ fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
|
|
|
|
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
|
|
|
+ (7<<6) | (1<<1), 1,
|
|
|
|
+ "READ TOC")) == 0)
|
|
|
|
+ reply = do_read_toc(fsg, bh);
|
|
|
|
+ break;
|
|
|
|
+
|
|
case SC_READ_FORMAT_CAPACITIES:
|
|
case SC_READ_FORMAT_CAPACITIES:
|
|
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
|
|
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
|
|
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
|
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
|
@@ -2933,6 +3047,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|
// Fall through
|
|
// Fall through
|
|
|
|
|
|
default:
|
|
default:
|
|
|
|
+ unknown_cmnd:
|
|
fsg->data_size_from_cmnd = 0;
|
|
fsg->data_size_from_cmnd = 0;
|
|
sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
|
|
sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
|
|
if ((reply = check_command(fsg, fsg->cmnd_size,
|
|
if ((reply = check_command(fsg, fsg->cmnd_size,
|
|
@@ -3498,6 +3613,7 @@ static int open_backing_file(struct lun *curlun, const char *filename)
|
|
struct inode *inode = NULL;
|
|
struct inode *inode = NULL;
|
|
loff_t size;
|
|
loff_t size;
|
|
loff_t num_sectors;
|
|
loff_t num_sectors;
|
|
|
|
+ loff_t min_sectors;
|
|
|
|
|
|
/* R/W if we can, R/O if we must */
|
|
/* R/W if we can, R/O if we must */
|
|
ro = curlun->ro;
|
|
ro = curlun->ro;
|
|
@@ -3541,8 +3657,19 @@ static int open_backing_file(struct lun *curlun, const char *filename)
|
|
rc = (int) size;
|
|
rc = (int) size;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
- num_sectors = size >> 9; // File size in 512-byte sectors
|
|
|
|
- if (num_sectors == 0) {
|
|
|
|
|
|
+ num_sectors = size >> 9; // File size in 512-byte blocks
|
|
|
|
+ min_sectors = 1;
|
|
|
|
+ if (mod_data.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;
|
|
|
|
+ LINFO(curlun, "file too big: %s\n", filename);
|
|
|
|
+ LINFO(curlun, "using only first %d blocks\n",
|
|
|
|
+ (int) num_sectors);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (num_sectors < min_sectors) {
|
|
LINFO(curlun, "file too small: %s\n", filename);
|
|
LINFO(curlun, "file too small: %s\n", filename);
|
|
rc = -ETOOSMALL;
|
|
rc = -ETOOSMALL;
|
|
goto out;
|
|
goto out;
|
|
@@ -3845,9 +3972,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
if (mod_data.removable) { // Enable the store_xxx attributes
|
|
if (mod_data.removable) { // Enable the store_xxx attributes
|
|
- dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;
|
|
|
|
- dev_attr_ro.store = store_ro;
|
|
|
|
|
|
+ dev_attr_file.attr.mode = 0644;
|
|
dev_attr_file.store = store_file;
|
|
dev_attr_file.store = store_file;
|
|
|
|
+ if (!mod_data.cdrom) {
|
|
|
|
+ dev_attr_ro.attr.mode = 0644;
|
|
|
|
+ dev_attr_ro.store = store_ro;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* Find out how many LUNs there should be */
|
|
/* Find out how many LUNs there should be */
|
|
@@ -3872,6 +4002,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|
for (i = 0; i < fsg->nluns; ++i) {
|
|
for (i = 0; i < fsg->nluns; ++i) {
|
|
curlun = &fsg->luns[i];
|
|
curlun = &fsg->luns[i];
|
|
curlun->ro = mod_data.ro[i];
|
|
curlun->ro = mod_data.ro[i];
|
|
|
|
+ if (mod_data.cdrom)
|
|
|
|
+ curlun->ro = 1;
|
|
curlun->dev.release = lun_release;
|
|
curlun->dev.release = lun_release;
|
|
curlun->dev.parent = &gadget->dev;
|
|
curlun->dev.parent = &gadget->dev;
|
|
curlun->dev.driver = &fsg_driver.driver;
|
|
curlun->dev.driver = &fsg_driver.driver;
|
|
@@ -4031,9 +4163,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
|
mod_data.protocol_name, mod_data.protocol_type);
|
|
mod_data.protocol_name, mod_data.protocol_type);
|
|
DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
|
|
DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
|
|
mod_data.vendor, mod_data.product, mod_data.release);
|
|
mod_data.vendor, mod_data.product, mod_data.release);
|
|
- DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
|
|
|
|
|
|
+ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
|
|
mod_data.removable, mod_data.can_stall,
|
|
mod_data.removable, mod_data.can_stall,
|
|
- mod_data.buflen);
|
|
|
|
|
|
+ mod_data.cdrom, mod_data.buflen);
|
|
DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
|
|
DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
|
|
|
|
|
|
set_bit(REGISTERED, &fsg->atomic_bitflags);
|
|
set_bit(REGISTERED, &fsg->atomic_bitflags);
|