X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Fstorage_common.c;h=04c462ff0ea6af1d6c8e6bf49926c3b1da15d396;hb=8018ab057480974e7f26a387bf4ce040e9a5f6f1;hp=affd23b5436f71e6d252b8fa89febb28ff098f08;hpb=e909ef5def59236b91fa9ee83446084eb6f48d1a;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index affd23b..04c462f 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -33,10 +33,38 @@ * macro is defined prior to including this file. */ +/* + * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and + * fsg_hs_intr_in_desc objects as well as + * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES + * macros are not defined. + * + * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, + * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not + * defined (as well as corresponding entries in string tables are + * missing) and FSG_STRING_INTERFACE has value of zero. + * + * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. + */ + +/* + * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included + * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN + * characters rather then a pointer to void. + */ + #include +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. */ +#define FSG_VENDOR_ID 0x0525 /* NetChip */ +#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + + /*-------------------------------------------------------------------------*/ @@ -56,18 +84,26 @@ #define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) #define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) -#define DBG(d, fmt, args...) dev_dbg (&(d)->gadget->dev, fmt, ## args) -#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev, fmt, ## args) -#define ERROR(d, fmt, args...) dev_err (&(d)->gadget->dev, fmt, ## args) -#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev, fmt, ## args) -#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev, fmt, ## args) +/* Keep those macros in sync with thos in + * include/linux/ubs/composite.h or else GCC will complain. If they + * are identical (the same names of arguments, white spaces in the + * same places) GCC will allow redefinition otherwise (even if some + * white space is removed or added) warning will be issued. No + * checking if those symbols is defined is performed because warning + * is desired when those macros were defined by someone else to mean + * something else. */ +#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) +#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) +#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) +#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) +#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args) #ifdef DUMP_MSGS # define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { \ + /* const u8 * */ buf, /* unsigned */ length) do { \ if (length < 512) { \ DBG(fsg, "%s, length %u:\n", label, length); \ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ @@ -80,11 +116,11 @@ #else # define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { } while (0) + /* const u8 * */ buf, /* unsigned */ length) do { } while (0) # ifdef VERBOSE_DEBUG -#define dump_cdb(fsg) \ +# define dump_cdb(fsg) \ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ @@ -107,45 +143,45 @@ #define TYPE_CDROM 0x05 /* USB protocol value = the transport method */ -#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt -#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt -#define USB_PR_BULK 0x50 // Bulk-only +#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */ +#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */ +#define USB_PR_BULK 0x50 /* Bulk-only */ /* USB subclass value = the protocol encapsulation */ -#define USB_SC_RBC 0x01 // Reduced Block Commands (flash) -#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM) -#define USB_SC_QIC 0x03 // QIC-157 (tape) -#define USB_SC_UFI 0x04 // UFI (floppy) -#define USB_SC_8070 0x05 // SFF-8070i (removable) -#define USB_SC_SCSI 0x06 // Transparent SCSI +#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */ +#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */ +#define USB_SC_QIC 0x03 /* QIC-157 (tape) */ +#define USB_SC_UFI 0x04 /* UFI (floppy) */ +#define USB_SC_8070 0x05 /* SFF-8070i (removable) */ +#define USB_SC_SCSI 0x06 /* Transparent SCSI */ /* Bulk-only data structures */ /* Command Block Wrapper */ struct fsg_bulk_cb_wrap { - __le32 Signature; // Contains 'USBC' - u32 Tag; // Unique per command id - __le32 DataTransferLength; // Size of the data - u8 Flags; // Direction in bit 7 - u8 Lun; // LUN (normally 0) - u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE - u8 CDB[16]; // Command Data Block + __le32 Signature; /* Contains 'USBC' */ + u32 Tag; /* Unique per command id */ + __le32 DataTransferLength; /* Size of the data */ + u8 Flags; /* Direction in bit 7 */ + u8 Lun; /* LUN (normally 0) */ + u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ + u8 CDB[16]; /* Command Data Block */ }; #define USB_BULK_CB_WRAP_LEN 31 -#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ #define USB_BULK_IN_FLAG 0x80 /* Command Status Wrapper */ struct bulk_cs_wrap { - __le32 Signature; // Should = 'USBS' - u32 Tag; // Same as original command - __le32 Residue; // Amount not transferred - u8 Status; // See below + __le32 Signature; /* Should = 'USBS' */ + u32 Tag; /* Same as original command */ + __le32 Residue; /* Amount not transferred */ + u8 Status; /* See below */ }; #define USB_BULK_CS_WRAP_LEN 13 -#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS' +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ #define USB_STATUS_PASS 0 #define USB_STATUS_FAIL 1 #define USB_STATUS_PHASE_ERROR 2 @@ -167,7 +203,8 @@ struct interrupt_data { #define USB_CBI_ADSC_REQUEST 0x00 -#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE 16 /* SCSI commands that we recognize */ #define SC_FORMAT_UNIT 0x04 @@ -212,7 +249,7 @@ struct interrupt_data { #define SS_WRITE_ERROR 0x030c02 #define SS_WRITE_PROTECTED 0x072700 -#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ #define ASC(x) ((u8) ((x) >> 8)) #define ASCQ(x) ((u8) (x)) @@ -225,13 +262,13 @@ struct fsg_lun { loff_t file_length; loff_t num_sectors; - unsigned int initially_ro : 1; - unsigned int ro : 1; - unsigned int removable : 1; - unsigned int cdrom : 1; - unsigned int prevent_medium_removal : 1; - unsigned int registered : 1; - unsigned int info_valid : 1; + unsigned int initially_ro:1; + unsigned int ro:1; + unsigned int removable:1; + unsigned int cdrom:1; + unsigned int prevent_medium_removal:1; + unsigned int registered:1; + unsigned int info_valid:1; u32 sense_data; u32 sense_data_info; @@ -250,11 +287,17 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev) /* Big enough to hold our biggest descriptor */ #define EP0_BUFSIZE 256 -#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value +#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ /* Number of buffers we will use. 2 is enough for double-buffering */ #define FSG_NUM_BUFFERS 2 +/* Default size of buffer length. */ +#define FSG_BUFLEN ((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS 8 + enum fsg_buffer_state { BUF_STATE_EMPTY = 0, BUF_STATE_FULL, @@ -262,7 +305,11 @@ enum fsg_buffer_state { }; struct fsg_buffhd { +#ifdef FSG_BUFFHD_STATIC_BUFFER + char buf[FSG_BUFLEN]; +#else void *buf; +#endif enum fsg_buffer_state state; struct fsg_buffhd *next; @@ -278,7 +325,8 @@ struct fsg_buffhd { }; enum fsg_state { - FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere + /* This one isn't used anywhere */ + FSG_STATE_COMMAND_PHASE = -10, FSG_STATE_DATA_PHASE, FSG_STATE_STATUS_PHASE, @@ -313,14 +361,17 @@ static inline u32 get_unaligned_be24(u8 *buf) enum { +#ifndef FSG_NO_DEVICE_STRINGS FSG_STRING_MANUFACTURER = 1, FSG_STRING_PRODUCT, FSG_STRING_SERIAL, FSG_STRING_CONFIG, +#endif FSG_STRING_INTERFACE }; +#ifndef FSG_NO_OTG static struct usb_otg_descriptor fsg_otg_desc = { .bLength = sizeof fsg_otg_desc, @@ -328,6 +379,7 @@ fsg_otg_desc = { .bmAttributes = USB_OTG_SRP, }; +#endif /* There is only one interface. */ @@ -336,10 +388,10 @@ fsg_intf_desc = { .bLength = sizeof fsg_intf_desc, .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 2, // Adjusted during fsg_bind() + .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() - .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() + .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ + .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, }; @@ -366,6 +418,8 @@ fsg_fs_bulk_out_desc = { /* wMaxPacketSize set by autoconfiguration */ }; +#ifndef FSG_NO_INTR_EP + static struct usb_endpoint_descriptor fsg_fs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -374,18 +428,29 @@ fsg_fs_intr_in_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 32, // frames -> 32 ms + .bInterval = 32, /* frames -> 32 ms */ }; -static const struct usb_descriptor_header *fsg_fs_function[] = { +#ifndef FSG_NO_OTG +# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 +#else +# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 +#endif + +#endif + +static struct usb_descriptor_header *fsg_fs_function[] = { +#ifndef FSG_NO_OTG (struct usb_descriptor_header *) &fsg_otg_desc, +#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, +#ifndef FSG_NO_INTR_EP (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, +#endif NULL, }; -#define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 /* @@ -414,9 +479,11 @@ fsg_hs_bulk_out_desc = { /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, // NAK every 1 uframe + .bInterval = 1, /* NAK every 1 uframe */ }; +#ifndef FSG_NO_INTR_EP + static struct usb_endpoint_descriptor fsg_hs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -425,18 +492,29 @@ fsg_hs_intr_in_desc = { /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms + .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ }; -static const struct usb_descriptor_header *fsg_hs_function[] = { +#ifndef FSG_NO_OTG +# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 +#else +# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 +#endif + +#endif + +static struct usb_descriptor_header *fsg_hs_function[] = { +#ifndef FSG_NO_OTG (struct usb_descriptor_header *) &fsg_otg_desc, +#endif (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, +#ifndef FSG_NO_INTR_EP (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, +#endif NULL, }; -#define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ static struct usb_endpoint_descriptor * @@ -451,16 +529,18 @@ fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string fsg_strings[] = { +#ifndef FSG_NO_DEVICE_STRINGS {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, {FSG_STRING_PRODUCT, fsg_string_product}, {FSG_STRING_SERIAL, fsg_string_serial}, {FSG_STRING_CONFIG, fsg_string_config}, +#endif {FSG_STRING_INTERFACE, fsg_string_interface}, {} }; static struct usb_gadget_strings fsg_stringtab = { - .language = 0x0409, // en-us + .language = 0x0409, /* en-us */ .strings = fsg_strings, }; @@ -522,11 +602,11 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) rc = (int) size; goto out; } - num_sectors = size >> 9; // File size in 512-byte blocks + 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 + 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); @@ -574,7 +654,7 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun) if (curlun->ro || !filp) return 0; - return vfs_fsync(filp, filp->f_path.dentry, 1); + return vfs_fsync(filp, 1); } static void store_cdrom_address(u8 *dest, int msf, u32 addr) @@ -594,3 +674,105 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr) put_unaligned_be32(addr, dest); } } + + +/*-------------------------------------------------------------------------*/ + + +static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) + ? curlun->ro + : curlun->initially_ro); +} + +static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + char *p; + ssize_t rc; + + down_read(filesem); + if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + if (IS_ERR(p)) + rc = PTR_ERR(p); + else { + rc = strlen(p); + memmove(buf, p, rc); + buf[rc] = '\n'; /* Add a newline */ + buf[++rc] = 0; + } + } else { /* No file, return 0 bytes */ + *buf = 0; + rc = 0; + } + up_read(filesem); + return rc; +} + + +static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t rc = count; + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + int i; + + if (sscanf(buf, "%d", &i) != 1) + return -EINVAL; + + /* Allow the write-enable status to change only while the backing file + * is closed. */ + down_read(filesem); + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + rc = -EBUSY; + } else { + curlun->ro = !!i; + curlun->initially_ro = !!i; + LDBG(curlun, "read-only status set to %d\n", curlun->ro); + } + up_read(filesem); + return rc; +} + +static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + int rc = 0; + + if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { + LDBG(curlun, "eject attempt prevented\n"); + return -EBUSY; /* "Door is locked" */ + } + + /* Remove a trailing newline */ + if (count > 0 && buf[count-1] == '\n') + ((char *) buf)[count-1] = 0; /* Ugh! */ + + /* Eject current medium */ + down_write(filesem); + if (fsg_lun_is_open(curlun)) { + fsg_lun_close(curlun); + curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; + } + + /* Load new medium */ + if (count > 0 && buf[0]) { + rc = fsg_lun_open(curlun, buf); + if (rc == 0) + curlun->unit_attention_data = + SS_NOT_READY_TO_READY_TRANSITION; + } + up_write(filesem); + return (rc < 0 ? rc : count); +}