* Required if "removable" is not set, names of
* the files or block devices used for
* backing storage
+ * serial=HHHH... Required serial number (string of hex chars)
* ro=b[,b...] Default false, booleans for read-only access
* removable Default false, boolean for removable media
* luns=N Default N = number of filenames, number of
* vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
* product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
* release=0xRRRR Override the USB release number (bcdDevice)
- * serial=HHHH... Override serial number (string of hex chars)
* buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of
* 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", "serial", "ro",
* "removable", "luns", "nofua", "stall", and "cdrom" options are available;
* default values are used for everything else.
*
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-/* DRIVER_VERSION must be at least 6 characters long, as it is used
- * to generate a fallback serial number. */
-#define DRIVER_VERSION "20 November 2008"
+#define DRIVER_VERSION "1 September 2010"
static char fsg_string_manufacturer[64];
static const char fsg_string_product[] = DRIVER_DESC;
-static char fsg_string_serial[13];
static const char fsg_string_config[] = "Self-powered";
static const char fsg_string_interface[] = "Mass Storage";
static struct {
char *file[FSG_MAX_LUNS];
+ char *serial;
int ro[FSG_MAX_LUNS];
int nofua[FSG_MAX_LUNS];
unsigned int num_filenames;
unsigned short vendor;
unsigned short product;
unsigned short release;
- char *serial;
unsigned int buflen;
int transport_type;
S_IRUGO);
MODULE_PARM_DESC(file, "names of backing files or devices");
+module_param_named(serial, mod_data.serial, charp, S_IRUGO);
+MODULE_PARM_DESC(serial, "USB serial number");
+
module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only");
module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
-module_param_named(serial, mod_data.serial, charp, S_IRUGO);
-MODULE_PARM_DESC(serial, "USB serial number");
-
/* In the non-TEST version, only the module parameters listed above
* are available. */
#ifdef CONFIG_USB_FILE_STORAGE_TEST
{
struct usb_request *req = fsg->ep0req;
static u8 cbi_reset_cmnd[6] = {
- SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
+ SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
/* Error in command transfer? */
if (req->status || req->length != req->actual ||
/* Get the starting Logical Block Address and check that it's
* not too big */
- if (fsg->cmnd[0] == SC_READ_6)
+ if (fsg->cmnd[0] == READ_6)
lba = get_unaligned_be24(&fsg->cmnd[1]);
else {
lba = get_unaligned_be32(&fsg->cmnd[2]);
/* Get the starting Logical Block Address and check that it's
* not too big */
- if (fsg->cmnd[0] == SC_WRITE_6)
+ if (fsg->cmnd[0] == WRITE_6)
lba = get_unaligned_be24(&fsg->cmnd[1]);
else {
lba = get_unaligned_be32(&fsg->cmnd[2]);
}
memset(buf, 0, 8);
- buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
+ buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
if (mod_data.removable)
buf[1] = 0x80;
buf[2] = 2; // ANSI SCSI level 2
* The only variable value is the WriteProtect bit. We will fill in
* the mode data length later. */
memset(buf, 0, 8);
- if (mscmnd == SC_MODE_SENSE_6) {
+ if (mscmnd == MODE_SENSE) {
buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
buf += 4;
limit = 255;
- } else { // SC_MODE_SENSE_10
+ } else { // MODE_SENSE_10
buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
buf += 8;
limit = 65535; // Should really be mod_data.buflen
}
/* Store the mode data length */
- if (mscmnd == SC_MODE_SENSE_6)
+ if (mscmnd == MODE_SENSE)
buf0[0] = len - 1;
else
put_unaligned_be16(len - 2, buf0);
/* Check the LUN */
if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
fsg->curlun = curlun = &fsg->luns[fsg->lun];
- if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ if (fsg->cmnd[0] != REQUEST_SENSE) {
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
curlun->info_valid = 0;
/* INQUIRY and REQUEST SENSE commands are explicitly allowed
* to use unsupported LUNs; all others may not. */
- if (fsg->cmnd[0] != SC_INQUIRY &&
- fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ if (fsg->cmnd[0] != INQUIRY &&
+ fsg->cmnd[0] != REQUEST_SENSE) {
DBG(fsg, "unsupported LUN %d\n", fsg->lun);
return -EINVAL;
}
/* If a unit attention condition exists, only INQUIRY and
* REQUEST SENSE commands are allowed; anything else must fail. */
if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
- fsg->cmnd[0] != SC_INQUIRY &&
- fsg->cmnd[0] != SC_REQUEST_SENSE) {
+ fsg->cmnd[0] != INQUIRY &&
+ fsg->cmnd[0] != REQUEST_SENSE) {
curlun->sense_data = curlun->unit_attention_data;
curlun->unit_attention_data = SS_NO_SENSE;
return -EINVAL;
down_read(&fsg->filesem); // We're using the backing file
switch (fsg->cmnd[0]) {
- case SC_INQUIRY:
+ case INQUIRY:
fsg->data_size_from_cmnd = fsg->cmnd[4];
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(1<<4), 0,
reply = do_inquiry(fsg, bh);
break;
- case SC_MODE_SELECT_6:
+ case MODE_SELECT:
fsg->data_size_from_cmnd = fsg->cmnd[4];
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
(1<<1) | (1<<4), 0,
reply = do_mode_select(fsg, bh);
break;
- case SC_MODE_SELECT_10:
+ case MODE_SELECT_10:
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (3<<7), 0,
reply = do_mode_select(fsg, bh);
break;
- case SC_MODE_SENSE_6:
+ case MODE_SENSE:
fsg->data_size_from_cmnd = fsg->cmnd[4];
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(1<<1) | (1<<2) | (1<<4), 0,
reply = do_mode_sense(fsg, bh);
break;
- case SC_MODE_SENSE_10:
+ case MODE_SENSE_10:
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (1<<2) | (3<<7), 0,
reply = do_mode_sense(fsg, bh);
break;
- case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ case ALLOW_MEDIUM_REMOVAL:
fsg->data_size_from_cmnd = 0;
if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
(1<<4), 0,
reply = do_prevent_allow(fsg);
break;
- case SC_READ_6:
+ case READ_6:
i = fsg->cmnd[4];
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
reply = do_read(fsg);
break;
- case SC_READ_10:
+ case READ_10:
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << 9;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
reply = do_read(fsg);
break;
- case SC_READ_12:
+ case READ_12:
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << 9;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
reply = do_read(fsg);
break;
- case SC_READ_CAPACITY:
+ case READ_CAPACITY:
fsg->data_size_from_cmnd = 8;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(0xf<<2) | (1<<8), 1,
reply = do_read_capacity(fsg, bh);
break;
- case SC_READ_HEADER:
+ case READ_HEADER:
if (!mod_data.cdrom)
goto unknown_cmnd;
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
reply = do_read_header(fsg, bh);
break;
- case SC_READ_TOC:
+ case READ_TOC:
if (!mod_data.cdrom)
goto unknown_cmnd;
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
reply = do_read_toc(fsg, bh);
break;
- case SC_READ_FORMAT_CAPACITIES:
+ case READ_FORMAT_CAPACITIES:
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(3<<7), 1,
reply = do_read_format_capacities(fsg, bh);
break;
- case SC_REQUEST_SENSE:
+ case REQUEST_SENSE:
fsg->data_size_from_cmnd = fsg->cmnd[4];
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(1<<4), 0,
reply = do_request_sense(fsg, bh);
break;
- case SC_START_STOP_UNIT:
+ case START_STOP:
fsg->data_size_from_cmnd = 0;
if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
(1<<1) | (1<<4), 0,
reply = do_start_stop(fsg);
break;
- case SC_SYNCHRONIZE_CACHE:
+ case SYNCHRONIZE_CACHE:
fsg->data_size_from_cmnd = 0;
if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
(0xf<<2) | (3<<7), 1,
reply = do_synchronize_cache(fsg);
break;
- case SC_TEST_UNIT_READY:
+ case TEST_UNIT_READY:
fsg->data_size_from_cmnd = 0;
reply = check_command(fsg, 6, DATA_DIR_NONE,
0, 1,
/* Although optional, this command is used by MS-Windows. We
* support a minimal version: BytChk must be 0. */
- case SC_VERIFY:
+ case VERIFY:
fsg->data_size_from_cmnd = 0;
if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
(1<<1) | (0xf<<2) | (3<<7), 1,
reply = do_verify(fsg);
break;
- case SC_WRITE_6:
+ case WRITE_6:
i = fsg->cmnd[4];
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
reply = do_write(fsg);
break;
- case SC_WRITE_10:
+ case WRITE_10:
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << 9;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
reply = do_write(fsg);
break;
- case SC_WRITE_12:
+ case WRITE_12:
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << 9;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
* 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 SC_FORMAT_UNIT:
- case SC_RELEASE:
- case SC_RESERVE:
- case SC_SEND_DIAGNOSTIC:
+ case FORMAT_UNIT:
+ case RELEASE:
+ case RESERVE:
+ case SEND_DIAGNOSTIC:
// Fall through
default:
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
if (curlun->registered) {
+ device_remove_file(&curlun->dev, &dev_attr_nofua);
device_remove_file(&curlun->dev, &dev_attr_ro);
device_remove_file(&curlun->dev, &dev_attr_file);
fsg_lun_close(curlun);
{
int prot;
int gcnum;
- int i;
/* Store the default values */
mod_data.transport_type = USB_PR_BULK;
if ((*ch < '0' || *ch > '9') &&
(*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
WARNING(fsg,
- "Invalid serial string character: %c; "
- "Failing back to default\n",
+ "Invalid serial string character: %c\n",
*ch);
- goto fill_serial;
+ goto no_serial;
}
}
if (len > 126 ||
(mod_data.transport_type == USB_PR_BULK && len < 12) ||
(mod_data.transport_type != USB_PR_BULK && len > 12)) {
- WARNING(fsg,
- "Invalid serial string length; "
- "Failing back to default\n");
- goto fill_serial;
+ WARNING(fsg, "Invalid serial string length!\n");
+ goto no_serial;
}
fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
} else {
- WARNING(fsg,
- "Userspace failed to provide serial number; "
- "Failing back to default\n");
-fill_serial:
- /* Serial number not specified or invalid, make our own.
- * We just encode it from the driver version string,
- * 12 characters to comply with both CB[I] and BBB spec.
- * Warning : Two devices running the same kernel will have
- * the same fallback serial number. */
- for (i = 0; i < 12; i += 2) {
- unsigned char c = DRIVER_VERSION[i / 2];
-
- if (!c)
- break;
- sprintf(&fsg_string_serial[i], "%02X", c);
- }
+ WARNING(fsg, "No serial-number string provided!\n");
+ no_serial:
+ device_desc.iSerialNumber = 0;
}
return 0;
}
-static int __ref fsg_bind(struct usb_gadget *gadget)
+static int __init fsg_bind(struct usb_gadget *gadget)
{
struct fsg_dev *fsg = the_fsg;
int rc;
dev_set_name(&curlun->dev,"%s-lun%d",
dev_name(&gadget->dev), i);
- if ((rc = device_register(&curlun->dev)) != 0) {
+ kref_get(&fsg->ref);
+ rc = device_register(&curlun->dev);
+ if (rc) {
INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
- goto out;
- }
- if ((rc = device_create_file(&curlun->dev,
- &dev_attr_ro)) != 0 ||
- (rc = device_create_file(&curlun->dev,
- &dev_attr_nofua)) != 0 ||
- (rc = device_create_file(&curlun->dev,
- &dev_attr_file)) != 0) {
- device_unregister(&curlun->dev);
+ put_device(&curlun->dev);
goto out;
}
curlun->registered = 1;
- kref_get(&fsg->ref);
+
+ rc = device_create_file(&curlun->dev, &dev_attr_ro);
+ if (rc)
+ goto out;
+ rc = device_create_file(&curlun->dev, &dev_attr_nofua);
+ if (rc)
+ goto out;
+ rc = device_create_file(&curlun->dev, &dev_attr_file);
+ if (rc)
+ goto out;
if (mod_data.file[i] && *mod_data.file[i]) {
- if ((rc = fsg_lun_open(curlun,
- mod_data.file[i])) != 0)
+ rc = fsg_lun_open(curlun, mod_data.file[i]);
+ if (rc)
goto out;
} else if (!mod_data.removable) {
ERROR(fsg, "no file given for LUN%d\n", i);
.speed = USB_SPEED_FULL,
#endif
.function = (char *) fsg_string_product,
- .bind = fsg_bind,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,
.setup = fsg_setup,
if ((rc = fsg_alloc()) != 0)
return rc;
fsg = the_fsg;
- if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
+ if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
kref_put(&fsg->ref, fsg_release);
return rc;
}