diff options
Diffstat (limited to 'drivers/usb/gadget/file_storage.c')
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 168 |
1 files changed, 107 insertions, 61 deletions
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index b49d86e3e45b..d4fdf65fb925 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -56,7 +56,7 @@ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by * the optional "protocol" module parameter. In addition, the default - * Vendor ID, Product ID, and release number can be overridden. + * Vendor ID, Product ID, release number and serial number can be overridden. * * There is support for multiple logical units (LUNs), each of which has * its own backing file. The number of LUNs can be set using the optional @@ -89,10 +89,13 @@ * 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 * LUNs to support + * nofua=b[,b...] Default false, booleans for ignore FUA flag + * in SCSI WRITE(10,12) commands * stall Default determined according to the type of * USB device controller (usually true), * boolean to permit the driver to halt @@ -110,13 +113,13 @@ * rounded down to a multiple of * PAGE_CACHE_SIZE) * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", - * "removable", "luns", "stall", and "cdrom" options are available; default - * values are used for everything else. + * 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. * * 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 - * gadget's sysfs directory. If the "removable" option is set, writing to + * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of + * the gadget's sysfs directory. If the "removable" option is set, writing to * these files will simulate ejecting/loading the medium (writing an empty * line means eject) and adjusting a write-enable tab. Changes to the ro * setting are not allowed when the medium is loaded or if CD-ROM emulation @@ -270,11 +273,10 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#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"; @@ -300,9 +302,12 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[FSG_MAX_LUNS]; + char *serial; int ro[FSG_MAX_LUNS]; + int nofua[FSG_MAX_LUNS]; unsigned int num_filenames; unsigned int num_ros; + unsigned int num_nofuas; unsigned int nluns; int removable; @@ -338,9 +343,16 @@ module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, 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_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, + S_IRUGO); +MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); + module_param_named(luns, mod_data.nluns, uint, S_IRUGO); MODULE_PARM_DESC(luns, "number of LUNs"); @@ -353,7 +365,6 @@ 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 * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -772,7 +783,7 @@ static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) { 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 || @@ -1124,7 +1135,7 @@ static int do_read(struct fsg_dev *fsg) /* 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]); @@ -1259,7 +1270,7 @@ static int do_write(struct fsg_dev *fsg) /* 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]); @@ -1272,7 +1283,8 @@ static int do_write(struct fsg_dev *fsg) curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - if (fsg->cmnd[1] & 0x08) { // FUA + /* FUA */ + if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { spin_lock(&curlun->filp->f_lock); curlun->filp->f_flags |= O_DSYNC; spin_unlock(&curlun->filp->f_lock); @@ -1566,7 +1578,7 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) } 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 @@ -1735,11 +1747,11 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) * 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 @@ -1779,7 +1791,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) } /* 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); @@ -2304,7 +2316,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, /* 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; @@ -2315,8 +2327,8 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, /* 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; } @@ -2325,8 +2337,8 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, /* 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; @@ -2376,7 +2388,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2384,7 +2396,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2392,7 +2404,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2400,7 +2412,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2408,7 +2420,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2416,7 +2428,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2424,7 +2436,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2433,7 +2445,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2442,7 +2454,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2451,7 +2463,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2459,7 +2471,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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]); @@ -2469,7 +2481,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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]); @@ -2479,7 +2491,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2487,7 +2499,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2495,7 +2507,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2503,7 +2515,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2511,7 +2523,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2520,7 +2532,7 @@ static int do_scsi_command(struct fsg_dev *fsg) /* 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, @@ -2528,7 +2540,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2537,7 +2549,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2546,7 +2558,7 @@ static int do_scsi_command(struct fsg_dev *fsg) 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, @@ -2559,10 +2571,10 @@ static int do_scsi_command(struct fsg_dev *fsg) * 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: @@ -3126,6 +3138,7 @@ static int fsg_main_thread(void *fsg_) /* The write permissions and store_xxx pointers are set in fsg_bind() */ static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); +static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); @@ -3162,6 +3175,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) 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); @@ -3272,8 +3286,44 @@ static int __init check_parameters(struct fsg_dev *fsg) ERROR(fsg, "invalid buflen\n"); return -ETOOSMALL; } + #endif /* CONFIG_USB_FILE_STORAGE_TEST */ + /* Serial string handling. + * On a real device, the serial string would be loaded + * from permanent storage. */ + if (mod_data.serial) { + const char *ch; + unsigned len = 0; + + /* Sanity check : + * The CB[I] specification limits the serial string to + * 12 uppercase hexadecimal characters. + * BBB need at least 12 uppercase hexadecimal characters, + * with a maximum of 126. */ + for (ch = mod_data.serial; *ch; ++ch) { + ++len; + if ((*ch < '0' || *ch > '9') && + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ + WARNING(fsg, + "Invalid serial string character: %c\n", + *ch); + 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!\n"); + goto no_serial; + } + fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; + } else { + WARNING(fsg, "No serial-number string provided!\n"); + no_serial: + device_desc.iSerialNumber = 0; + } + return 0; } @@ -3305,6 +3355,10 @@ static int __init fsg_bind(struct usb_gadget *gadget) } } + /* Only for removable media? */ + dev_attr_nofua.attr.mode = 0644; + dev_attr_nofua.store = fsg_store_nofua; + /* Find out how many LUNs there should be */ i = mod_data.nluns; if (i == 0) @@ -3330,6 +3384,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) curlun->ro = mod_data.cdrom || mod_data.ro[i]; curlun->initially_ro = curlun->ro; curlun->removable = mod_data.removable; + curlun->nofua = mod_data.nofua[i]; curlun->dev.release = lun_release; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; @@ -3344,6 +3399,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) 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); goto out; @@ -3447,16 +3504,6 @@ static int __init fsg_bind(struct usb_gadget *gadget) init_utsname()->sysname, init_utsname()->release, gadget->name); - /* On a real device, serial[] would be loaded from permanent - * storage. We just encode it from the driver version string. */ - for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) { - unsigned char c = DRIVER_VERSION[i / 2]; - - if (!c) - break; - sprintf(&fsg_string_serial[i], "%02X", c); - } - fsg->thread_task = kthread_create(fsg_main_thread, fsg, "file-storage-gadget"); if (IS_ERR(fsg->thread_task)) { @@ -3478,8 +3525,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (IS_ERR(p)) p = NULL; } - LINFO(curlun, "ro=%d, file: %s\n", - curlun->ro, (p ? p : "(error)")); + LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", + curlun->ro, curlun->nofua, (p ? p : "(error)")); } } kfree(pathbuf); @@ -3541,7 +3588,6 @@ static struct usb_gadget_driver fsg_driver = { .speed = USB_SPEED_FULL, #endif .function = (char *) fsg_string_product, - .bind = fsg_bind, .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, @@ -3583,7 +3629,7 @@ static int __init fsg_init(void) 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; } |