diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-09-28 19:01:48 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-09-28 19:01:48 -0700 |
| commit | 56df444494ad03afc57e2f2d917377a09c3ff89b (patch) | |
| tree | 53218969c46c6e95482addf12b4ae64fd6611e7d | |
| parent | dcf49f00a8e3c08f6484ba259e8d524aaac97881 (diff) | |
| download | patches-56df444494ad03afc57e2f2d917377a09c3ff89b.tar.gz | |
uas driver patch
| -rw-r--r-- | series | 4 | ||||
| -rw-r--r-- | usb/usb-add-uas-driver.patch | 828 | ||||
| -rw-r--r-- | usb/usb-gadget-file_storage-reuse-definitions-from-a-header-file.patch | 196 | ||||
| -rw-r--r-- | usb/usb-move-usb-storage-definitions-to-their-own-header-file.patch | 117 |
4 files changed, 1144 insertions, 1 deletions
@@ -149,10 +149,12 @@ usb/usb-serial-enable-usb-autosuspend-by-default-on-qcserial.patch usb/usb-ftdi_sio-revert-usb-ftdi_sio-fix-dtr-rts-line-modes.patch usb/usb-cdc.h-ncm-fix-one-more-typo.patch usb/usb-qcserial-enable-diagnostics-monitor-and-gps-ports-on-gobi-2000.patch +usb/usb-move-usb-storage-definitions-to-their-own-header-file.patch +usb/usb-add-uas-driver.patch +usb/usb-gadget-file_storage-reuse-definitions-from-a-header-file.patch # staging stuff for next is now in the staging-next tree on git.kernel.org - diff --git a/usb/usb-add-uas-driver.patch b/usb/usb-add-uas-driver.patch new file mode 100644 index 00000000000000..978327b2463586 --- /dev/null +++ b/usb/usb-add-uas-driver.patch @@ -0,0 +1,828 @@ +From willy@linux.intel.com Tue Sep 28 18:53:35 2010 +From: Matthew Wilcox <willy@linux.intel.com> +Date: Tue, 28 Sep 2010 06:14:56 -0400 +Subject: USB: Add UAS driver +To: greg@kroah.com, linux-usb@vger.kernel.org, linux-scsi@vger.kernel.org, sarah.a.sharp@linux.intel.com +Cc: Matthew Wilcox <matthew.r.wilcox@intel.com>, Matthew Wilcox <willy@linux.intel.com> +Message-ID: <1285668896-6356-2-git-send-email-willy@linux.intel.com> + + +From: Matthew Wilcox <matthew.r.wilcox@intel.com> + +USB Attached SCSI is a new protocol specified jointly by the SCSI T10 +committee and the USB Implementors Forum. + +Signed-off-by: Matthew Wilcox <willy@linux.intel.com> +Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + MAINTAINERS | 8 + drivers/usb/storage/Kconfig | 13 + drivers/usb/storage/Makefile | 1 + drivers/usb/storage/uas.c | 751 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 773 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -5898,6 +5898,14 @@ S: Maintained + F: Documentation/usb/acm.txt + F: drivers/usb/class/cdc-acm.* + ++USB ATTACHED SCSI ++M: Matthew Wilcox <willy@linux.intel.com> ++M: Sarah Sharp <sarah.a.sharp@linux.intel.com> ++L: linux-usb@vger.kernel.org ++L: linux-scsi@vger.kernel.org ++S: Supported ++F: drivers/usb/storage/uas.c ++ + USB BLOCK DRIVER (UB ub) + M: Pete Zaitcev <zaitcev@redhat.com> + L: linux-usb@vger.kernel.org +--- a/drivers/usb/storage/Kconfig ++++ b/drivers/usb/storage/Kconfig +@@ -172,6 +172,19 @@ config USB_STORAGE_CYPRESS_ATACB + + If this driver is compiled as a module, it will be named ums-cypress. + ++config USB_UAS ++ tristate "USB Attached SCSI" ++ depends on USB && SCSI ++ help ++ The USB Attached SCSI protocol is supported by some USB ++ storage devices. It permits higher performance by supporting ++ multiple outstanding commands. ++ ++ If you don't know whether you have a UAS device, it is safe to ++ say 'Y' or 'M' here and the kernel will use the right driver. ++ ++ If you compile this driver as a module, it will be named uas. ++ + config USB_LIBUSUAL + bool "The shared table of common (or usual) storage devices" + depends on USB +--- a/drivers/usb/storage/Makefile ++++ b/drivers/usb/storage/Makefile +@@ -7,6 +7,7 @@ + + EXTRA_CFLAGS := -Idrivers/scsi + ++obj-$(CONFIG_USB_UAS) += uas.o + obj-$(CONFIG_USB_STORAGE) += usb-storage.o + + usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o +--- /dev/null ++++ b/drivers/usb/storage/uas.c +@@ -0,0 +1,751 @@ ++/* ++ * USB Attached SCSI ++ * Note that this is not the same as the USB Mass Storage driver ++ * ++ * Copyright Matthew Wilcox for Intel Corp, 2010 ++ * Copyright Sarah Sharp for Intel Corp, 2010 ++ * ++ * Distributed under the terms of the GNU GPL, version two. ++ */ ++ ++#include <linux/blkdev.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/usb.h> ++#include <linux/usb/storage.h> ++ ++#include <scsi/scsi.h> ++#include <scsi/scsi_dbg.h> ++#include <scsi/scsi_cmnd.h> ++#include <scsi/scsi_device.h> ++#include <scsi/scsi_host.h> ++#include <scsi/scsi_tcq.h> ++ ++/* Common header for all IUs */ ++struct iu { ++ __u8 iu_id; ++ __u8 rsvd1; ++ __be16 tag; ++}; ++ ++enum { ++ IU_ID_COMMAND = 0x01, ++ IU_ID_STATUS = 0x03, ++ IU_ID_RESPONSE = 0x04, ++ IU_ID_TASK_MGMT = 0x05, ++ IU_ID_READ_READY = 0x06, ++ IU_ID_WRITE_READY = 0x07, ++}; ++ ++struct command_iu { ++ __u8 iu_id; ++ __u8 rsvd1; ++ __be16 tag; ++ __u8 prio_attr; ++ __u8 rsvd5; ++ __u8 len; ++ __u8 rsvd7; ++ struct scsi_lun lun; ++ __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */ ++}; ++ ++struct sense_iu { ++ __u8 iu_id; ++ __u8 rsvd1; ++ __be16 tag; ++ __be16 status_qual; ++ __u8 status; ++ __u8 service_response; ++ __u8 rsvd8[6]; ++ __be16 len; ++ __u8 sense[SCSI_SENSE_BUFFERSIZE]; ++}; ++ ++/* ++ * The r00-r01c specs define this version of the SENSE IU data structure. ++ * It's still in use by several different firmware releases. ++ */ ++struct sense_iu_old { ++ __u8 iu_id; ++ __u8 rsvd1; ++ __be16 tag; ++ __be16 len; ++ __u8 status; ++ __u8 service_response; ++ __u8 sense[SCSI_SENSE_BUFFERSIZE]; ++}; ++ ++enum { ++ CMD_PIPE_ID = 1, ++ STATUS_PIPE_ID = 2, ++ DATA_IN_PIPE_ID = 3, ++ DATA_OUT_PIPE_ID = 4, ++ ++ UAS_SIMPLE_TAG = 0, ++ UAS_HEAD_TAG = 1, ++ UAS_ORDERED_TAG = 2, ++ UAS_ACA = 4, ++}; ++ ++struct uas_dev_info { ++ struct usb_interface *intf; ++ struct usb_device *udev; ++ int qdepth; ++ unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; ++ unsigned use_streams:1; ++ unsigned uas_sense_old:1; ++}; ++ ++enum { ++ ALLOC_SENSE_URB = (1 << 0), ++ SUBMIT_SENSE_URB = (1 << 1), ++ ALLOC_DATA_IN_URB = (1 << 2), ++ SUBMIT_DATA_IN_URB = (1 << 3), ++ ALLOC_DATA_OUT_URB = (1 << 4), ++ SUBMIT_DATA_OUT_URB = (1 << 5), ++ ALLOC_CMD_URB = (1 << 6), ++ SUBMIT_CMD_URB = (1 << 7), ++}; ++ ++/* Overrides scsi_pointer */ ++struct uas_cmd_info { ++ unsigned int state; ++ unsigned int stream; ++ struct urb *cmd_urb; ++ struct urb *sense_urb; ++ struct urb *data_in_urb; ++ struct urb *data_out_urb; ++ struct list_head list; ++}; ++ ++/* I hate forward declarations, but I actually have a loop */ ++static int uas_submit_urbs(struct scsi_cmnd *cmnd, ++ struct uas_dev_info *devinfo, gfp_t gfp); ++ ++static DEFINE_SPINLOCK(uas_work_lock); ++static LIST_HEAD(uas_work_list); ++ ++static void uas_do_work(struct work_struct *work) ++{ ++ struct uas_cmd_info *cmdinfo; ++ struct list_head list; ++ ++ spin_lock_irq(&uas_work_lock); ++ list_replace_init(&uas_work_list, &list); ++ spin_unlock_irq(&uas_work_lock); ++ ++ list_for_each_entry(cmdinfo, &list, list) { ++ struct scsi_pointer *scp = (void *)cmdinfo; ++ struct scsi_cmnd *cmnd = container_of(scp, ++ struct scsi_cmnd, SCp); ++ uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_KERNEL); ++ } ++} ++ ++static DECLARE_WORK(uas_work, uas_do_work); ++ ++static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) ++{ ++ struct sense_iu *sense_iu = urb->transfer_buffer; ++ struct scsi_device *sdev = cmnd->device; ++ ++ if (urb->actual_length > 16) { ++ unsigned len = be16_to_cpup(&sense_iu->len); ++ if (len + 16 != urb->actual_length) { ++ int newlen = min(len + 16, urb->actual_length) - 16; ++ if (newlen < 0) ++ newlen = 0; ++ sdev_printk(KERN_INFO, sdev, "%s: urb length %d " ++ "disagrees with IU sense data length %d, " ++ "using %d bytes of sense data\n", __func__, ++ urb->actual_length, len, newlen); ++ len = newlen; ++ } ++ memcpy(cmnd->sense_buffer, sense_iu->sense, len); ++ } ++ ++ cmnd->result = sense_iu->status; ++ if (sdev->current_cmnd) ++ sdev->current_cmnd = NULL; ++ cmnd->scsi_done(cmnd); ++ usb_free_urb(urb); ++} ++ ++static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) ++{ ++ struct sense_iu_old *sense_iu = urb->transfer_buffer; ++ struct scsi_device *sdev = cmnd->device; ++ ++ if (urb->actual_length > 8) { ++ unsigned len = be16_to_cpup(&sense_iu->len) - 2; ++ if (len + 8 != urb->actual_length) { ++ int newlen = min(len + 8, urb->actual_length) - 8; ++ if (newlen < 0) ++ newlen = 0; ++ sdev_printk(KERN_INFO, sdev, "%s: urb length %d " ++ "disagrees with IU sense data length %d, " ++ "using %d bytes of sense data\n", __func__, ++ urb->actual_length, len, newlen); ++ len = newlen; ++ } ++ memcpy(cmnd->sense_buffer, sense_iu->sense, len); ++ } ++ ++ cmnd->result = sense_iu->status; ++ if (sdev->current_cmnd) ++ sdev->current_cmnd = NULL; ++ cmnd->scsi_done(cmnd); ++ usb_free_urb(urb); ++} ++ ++static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, ++ unsigned direction) ++{ ++ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; ++ int err; ++ ++ cmdinfo->state = direction | SUBMIT_SENSE_URB; ++ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); ++ if (err) { ++ spin_lock(&uas_work_lock); ++ list_add_tail(&cmdinfo->list, &uas_work_list); ++ spin_unlock(&uas_work_lock); ++ schedule_work(&uas_work); ++ } ++} ++ ++static void uas_stat_cmplt(struct urb *urb) ++{ ++ struct iu *iu = urb->transfer_buffer; ++ struct scsi_device *sdev = urb->context; ++ struct uas_dev_info *devinfo = sdev->hostdata; ++ struct scsi_cmnd *cmnd; ++ u16 tag; ++ ++ if (urb->status) { ++ dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); ++ usb_free_urb(urb); ++ return; ++ } ++ ++ tag = be16_to_cpup(&iu->tag) - 1; ++ if (sdev->current_cmnd) ++ cmnd = sdev->current_cmnd; ++ else ++ cmnd = scsi_find_tag(sdev, tag); ++ if (!cmnd) ++ return; ++ ++ switch (iu->iu_id) { ++ case IU_ID_STATUS: ++ if (urb->actual_length < 16) ++ devinfo->uas_sense_old = 1; ++ if (devinfo->uas_sense_old) ++ uas_sense_old(urb, cmnd); ++ else ++ uas_sense(urb, cmnd); ++ break; ++ case IU_ID_READ_READY: ++ uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); ++ break; ++ case IU_ID_WRITE_READY: ++ uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); ++ break; ++ default: ++ scmd_printk(KERN_ERR, cmnd, ++ "Bogus IU (%d) received on status pipe\n", iu->iu_id); ++ } ++} ++ ++static void uas_data_cmplt(struct urb *urb) ++{ ++ struct scsi_data_buffer *sdb = urb->context; ++ sdb->resid = sdb->length - urb->actual_length; ++ usb_free_urb(urb); ++} ++ ++static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, ++ unsigned int pipe, u16 stream_id, ++ struct scsi_data_buffer *sdb, ++ enum dma_data_direction dir) ++{ ++ struct usb_device *udev = devinfo->udev; ++ struct urb *urb = usb_alloc_urb(0, gfp); ++ ++ if (!urb) ++ goto out; ++ usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt, ++ sdb); ++ if (devinfo->use_streams) ++ urb->stream_id = stream_id; ++ urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; ++ urb->sg = sdb->table.sgl; ++ out: ++ return urb; ++} ++ ++static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, ++ struct scsi_cmnd *cmnd, u16 stream_id) ++{ ++ struct usb_device *udev = devinfo->udev; ++ struct urb *urb = usb_alloc_urb(0, gfp); ++ struct sense_iu *iu; ++ ++ if (!urb) ++ goto out; ++ ++ iu = kmalloc(sizeof(*iu), gfp); ++ if (!iu) ++ goto free; ++ ++ usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), ++ uas_stat_cmplt, cmnd->device); ++ urb->stream_id = stream_id; ++ urb->transfer_flags |= URB_FREE_BUFFER; ++ out: ++ return urb; ++ free: ++ usb_free_urb(urb); ++ return NULL; ++} ++ ++static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, ++ struct scsi_cmnd *cmnd, u16 stream_id) ++{ ++ struct usb_device *udev = devinfo->udev; ++ struct scsi_device *sdev = cmnd->device; ++ struct urb *urb = usb_alloc_urb(0, gfp); ++ struct command_iu *iu; ++ int len; ++ ++ if (!urb) ++ goto out; ++ ++ len = cmnd->cmd_len - 16; ++ if (len < 0) ++ len = 0; ++ len = ALIGN(len, 4); ++ iu = kmalloc(sizeof(*iu) + len, gfp); ++ if (!iu) ++ goto free; ++ ++ iu->iu_id = IU_ID_COMMAND; ++ iu->tag = cpu_to_be16(stream_id); ++ if (sdev->ordered_tags && (cmnd->request->cmd_flags & REQ_HARDBARRIER)) ++ iu->prio_attr = UAS_ORDERED_TAG; ++ else ++ iu->prio_attr = UAS_SIMPLE_TAG; ++ iu->len = len; ++ int_to_scsilun(sdev->lun, &iu->lun); ++ memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len); ++ ++ usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len, ++ usb_free_urb, NULL); ++ urb->transfer_flags |= URB_FREE_BUFFER; ++ out: ++ return urb; ++ free: ++ usb_free_urb(urb); ++ return NULL; ++} ++ ++/* ++ * Why should I request the Status IU before sending the Command IU? Spec ++ * says to, but also says the device may receive them in any order. Seems ++ * daft to me. ++ */ ++ ++static int uas_submit_urbs(struct scsi_cmnd *cmnd, ++ struct uas_dev_info *devinfo, gfp_t gfp) ++{ ++ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; ++ ++ if (cmdinfo->state & ALLOC_SENSE_URB) { ++ cmdinfo->sense_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, ++ cmdinfo->stream); ++ if (!cmdinfo->sense_urb) ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ cmdinfo->state &= ~ALLOC_SENSE_URB; ++ } ++ ++ if (cmdinfo->state & SUBMIT_SENSE_URB) { ++ if (usb_submit_urb(cmdinfo->sense_urb, gfp)) { ++ scmd_printk(KERN_INFO, cmnd, ++ "sense urb submission failure\n"); ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ cmdinfo->state &= ~SUBMIT_SENSE_URB; ++ } ++ ++ if (cmdinfo->state & ALLOC_DATA_IN_URB) { ++ cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, ++ devinfo->data_in_pipe, cmdinfo->stream, ++ scsi_in(cmnd), DMA_FROM_DEVICE); ++ if (!cmdinfo->data_in_urb) ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ cmdinfo->state &= ~ALLOC_DATA_IN_URB; ++ } ++ ++ if (cmdinfo->state & SUBMIT_DATA_IN_URB) { ++ if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) { ++ scmd_printk(KERN_INFO, cmnd, ++ "data in urb submission failure\n"); ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ cmdinfo->state &= ~SUBMIT_DATA_IN_URB; ++ } ++ ++ if (cmdinfo->state & ALLOC_DATA_OUT_URB) { ++ cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, ++ devinfo->data_out_pipe, cmdinfo->stream, ++ scsi_out(cmnd), DMA_TO_DEVICE); ++ if (!cmdinfo->data_out_urb) ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ cmdinfo->state &= ~ALLOC_DATA_OUT_URB; ++ } ++ ++ if (cmdinfo->state & SUBMIT_DATA_OUT_URB) { ++ if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) { ++ scmd_printk(KERN_INFO, cmnd, ++ "data out urb submission failure\n"); ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; ++ } ++ ++ if (cmdinfo->state & ALLOC_CMD_URB) { ++ cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd, ++ cmdinfo->stream); ++ if (!cmdinfo->cmd_urb) ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ cmdinfo->state &= ~ALLOC_CMD_URB; ++ } ++ ++ if (cmdinfo->state & SUBMIT_CMD_URB) { ++ if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) { ++ scmd_printk(KERN_INFO, cmnd, ++ "cmd urb submission failure\n"); ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ cmdinfo->state &= ~SUBMIT_CMD_URB; ++ } ++ ++ return 0; ++} ++ ++static int uas_queuecommand(struct scsi_cmnd *cmnd, ++ void (*done)(struct scsi_cmnd *)) ++{ ++ struct scsi_device *sdev = cmnd->device; ++ struct uas_dev_info *devinfo = sdev->hostdata; ++ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; ++ int err; ++ ++ BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); ++ ++ if (!cmdinfo->sense_urb && sdev->current_cmnd) ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ ++ if (blk_rq_tagged(cmnd->request)) { ++ cmdinfo->stream = cmnd->request->tag + 1; ++ } else { ++ sdev->current_cmnd = cmnd; ++ cmdinfo->stream = 1; ++ } ++ ++ cmnd->scsi_done = done; ++ ++ cmdinfo->state = ALLOC_SENSE_URB | SUBMIT_SENSE_URB | ++ ALLOC_CMD_URB | SUBMIT_CMD_URB; ++ ++ switch (cmnd->sc_data_direction) { ++ case DMA_FROM_DEVICE: ++ cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; ++ break; ++ case DMA_BIDIRECTIONAL: ++ cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; ++ case DMA_TO_DEVICE: ++ cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB; ++ case DMA_NONE: ++ break; ++ } ++ ++ if (!devinfo->use_streams) { ++ cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); ++ cmdinfo->stream = 0; ++ } ++ ++ err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); ++ if (err) { ++ /* If we did nothing, give up now */ ++ if (cmdinfo->state & SUBMIT_SENSE_URB) { ++ usb_free_urb(cmdinfo->sense_urb); ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ spin_lock(&uas_work_lock); ++ list_add_tail(&cmdinfo->list, &uas_work_list); ++ spin_unlock(&uas_work_lock); ++ schedule_work(&uas_work); ++ } ++ ++ return 0; ++} ++ ++static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) ++{ ++ struct scsi_device *sdev = cmnd->device; ++ sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, ++ cmnd->request->tag); ++ ++/* XXX: Send ABORT TASK Task Management command */ ++ return FAILED; ++} ++ ++static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) ++{ ++ struct scsi_device *sdev = cmnd->device; ++ sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, ++ cmnd->request->tag); ++ ++/* XXX: Send LOGICAL UNIT RESET Task Management command */ ++ return FAILED; ++} ++ ++static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd) ++{ ++ struct scsi_device *sdev = cmnd->device; ++ sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, ++ cmnd->request->tag); ++ ++/* XXX: Can we reset just the one USB interface? ++ * Would calling usb_set_interface() have the right effect? ++ */ ++ return FAILED; ++} ++ ++static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) ++{ ++ struct scsi_device *sdev = cmnd->device; ++ struct uas_dev_info *devinfo = sdev->hostdata; ++ struct usb_device *udev = devinfo->udev; ++ ++ sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, ++ cmnd->request->tag); ++ ++ if (usb_reset_device(udev)) ++ return SUCCESS; ++ ++ return FAILED; ++} ++ ++static int uas_slave_alloc(struct scsi_device *sdev) ++{ ++ sdev->hostdata = (void *)sdev->host->hostdata[0]; ++ return 0; ++} ++ ++static int uas_slave_configure(struct scsi_device *sdev) ++{ ++ struct uas_dev_info *devinfo = sdev->hostdata; ++ scsi_set_tag_type(sdev, MSG_ORDERED_TAG); ++ scsi_activate_tcq(sdev, devinfo->qdepth - 1); ++ return 0; ++} ++ ++static struct scsi_host_template uas_host_template = { ++ .module = THIS_MODULE, ++ .name = "uas", ++ .queuecommand = uas_queuecommand, ++ .slave_alloc = uas_slave_alloc, ++ .slave_configure = uas_slave_configure, ++ .eh_abort_handler = uas_eh_abort_handler, ++ .eh_device_reset_handler = uas_eh_device_reset_handler, ++ .eh_target_reset_handler = uas_eh_target_reset_handler, ++ .eh_bus_reset_handler = uas_eh_bus_reset_handler, ++ .can_queue = 65536, /* Is there a limit on the _host_ ? */ ++ .this_id = -1, ++ .sg_tablesize = SG_NONE, ++ .cmd_per_lun = 1, /* until we override it */ ++ .skip_settle_delay = 1, ++ .ordered_tag = 1, ++}; ++ ++static struct usb_device_id uas_usb_ids[] = { ++ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, ++ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_UAS) }, ++ /* 0xaa is a prototype device I happen to have access to */ ++ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, 0xaa) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(usb, uas_usb_ids); ++ ++static void uas_configure_endpoints(struct uas_dev_info *devinfo) ++{ ++ struct usb_host_endpoint *eps[4] = { }; ++ struct usb_interface *intf = devinfo->intf; ++ struct usb_device *udev = devinfo->udev; ++ struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint; ++ unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; ++ ++ devinfo->uas_sense_old = 0; ++ ++ for (i = 0; i < n_endpoints; i++) { ++ unsigned char *extra = endpoint[i].extra; ++ int len = endpoint[i].extralen; ++ while (len > 1) { ++ if (extra[1] == USB_DT_PIPE_USAGE) { ++ unsigned pipe_id = extra[2]; ++ if (pipe_id > 0 && pipe_id < 5) ++ eps[pipe_id - 1] = &endpoint[i]; ++ break; ++ } ++ len -= extra[0]; ++ extra += extra[0]; ++ } ++ } ++ ++ /* ++ * Assume that if we didn't find a control pipe descriptor, we're ++ * using a device with old firmware that happens to be set up like ++ * this. ++ */ ++ if (!eps[0]) { ++ devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1); ++ devinfo->status_pipe = usb_rcvbulkpipe(udev, 1); ++ devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); ++ devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); ++ ++ eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe); ++ eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); ++ eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); ++ } else { ++ devinfo->cmd_pipe = usb_sndbulkpipe(udev, ++ eps[0]->desc.bEndpointAddress); ++ devinfo->status_pipe = usb_rcvbulkpipe(udev, ++ eps[1]->desc.bEndpointAddress); ++ devinfo->data_in_pipe = usb_rcvbulkpipe(udev, ++ eps[2]->desc.bEndpointAddress); ++ devinfo->data_out_pipe = usb_sndbulkpipe(udev, ++ eps[3]->desc.bEndpointAddress); ++ } ++ ++ devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256, ++ GFP_KERNEL); ++ if (devinfo->qdepth < 0) { ++ devinfo->qdepth = 256; ++ devinfo->use_streams = 0; ++ } else { ++ devinfo->use_streams = 1; ++ } ++} ++ ++/* ++ * XXX: What I'd like to do here is register a SCSI host for each USB host in ++ * the system. Follow usb-storage's design of registering a SCSI host for ++ * each USB device for the moment. Can implement this by walking up the ++ * USB hierarchy until we find a USB host. ++ */ ++static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ++{ ++ int result; ++ struct Scsi_Host *shost; ++ struct uas_dev_info *devinfo; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ ++ if (id->bInterfaceProtocol == 0x50) { ++ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; ++/* XXX: Shouldn't assume that 1 is the alternative we want */ ++ int ret = usb_set_interface(udev, ifnum, 1); ++ if (ret) ++ return -ENODEV; ++ } ++ ++ devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL); ++ if (!devinfo) ++ return -ENOMEM; ++ ++ result = -ENOMEM; ++ shost = scsi_host_alloc(&uas_host_template, sizeof(void *)); ++ if (!shost) ++ goto free; ++ ++ shost->max_cmd_len = 16 + 252; ++ shost->max_id = 1; ++ shost->sg_tablesize = udev->bus->sg_tablesize; ++ ++ result = scsi_add_host(shost, &intf->dev); ++ if (result) ++ goto free; ++ shost->hostdata[0] = (unsigned long)devinfo; ++ ++ devinfo->intf = intf; ++ devinfo->udev = udev; ++ uas_configure_endpoints(devinfo); ++ ++ scsi_scan_host(shost); ++ usb_set_intfdata(intf, shost); ++ return result; ++ free: ++ kfree(devinfo); ++ if (shost) ++ scsi_host_put(shost); ++ return result; ++} ++ ++static int uas_pre_reset(struct usb_interface *intf) ++{ ++/* XXX: Need to return 1 if it's not our device in error handling */ ++ return 0; ++} ++ ++static int uas_post_reset(struct usb_interface *intf) ++{ ++/* XXX: Need to return 1 if it's not our device in error handling */ ++ return 0; ++} ++ ++static void uas_disconnect(struct usb_interface *intf) ++{ ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_host_endpoint *eps[3]; ++ struct Scsi_Host *shost = usb_get_intfdata(intf); ++ struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; ++ ++ scsi_remove_host(shost); ++ ++ eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); ++ eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); ++ eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); ++ usb_free_streams(intf, eps, 3, GFP_KERNEL); ++ ++ kfree(devinfo); ++} ++ ++/* ++ * XXX: Should this plug into libusual so we can auto-upgrade devices from ++ * Bulk-Only to UAS? ++ */ ++static struct usb_driver uas_driver = { ++ .name = "uas", ++ .probe = uas_probe, ++ .disconnect = uas_disconnect, ++ .pre_reset = uas_pre_reset, ++ .post_reset = uas_post_reset, ++ .id_table = uas_usb_ids, ++}; ++ ++static int uas_init(void) ++{ ++ return usb_register(&uas_driver); ++} ++ ++static void uas_exit(void) ++{ ++ usb_deregister(&uas_driver); ++} ++ ++module_init(uas_init); ++module_exit(uas_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp"); diff --git a/usb/usb-gadget-file_storage-reuse-definitions-from-a-header-file.patch b/usb/usb-gadget-file_storage-reuse-definitions-from-a-header-file.patch new file mode 100644 index 00000000000000..641ffb338f96d5 --- /dev/null +++ b/usb/usb-gadget-file_storage-reuse-definitions-from-a-header-file.patch @@ -0,0 +1,196 @@ +From m.nazarewicz@samsung.com Tue Sep 28 18:56:38 2010 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Date: Tue, 28 Sep 2010 12:55:32 +0200 +Subject: USB: gadget: file_storage: reuse definitions from a header file +To: Matthew Wilcox <willy@linux.intel.com>, greg@kroah.com +Cc: sarah.a.sharp@linux.intel.com, Michal Nazarewicz <mina86@mina86.com>, Alan Stern <stern@rowland.harvard.edu> +Message-ID: <5d4c116b32f9e6c45bb09eb6f28d5ef2e1b26c1f.1285670575.git.mina86@mina86.com> + + +From: Michal Nazarewicz <mina86@mina86.com> + +This commit changes storage_common.c and file_storage.c to +reuse definitions from linux/usb/storage.h header file. + +Signed-off-by: Michal Nazarewicz <mina86@mina86.com> +Cc: Alan Stern <stern@rowland.harvard.edu> +Cc: Matthew Wilcox <willy@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/file_storage.c | 50 ++++++++++++++++++------------------ + drivers/usb/gadget/storage_common.c | 18 ++---------- + 2 files changed, 28 insertions(+), 40 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -400,9 +400,9 @@ MODULE_PARM_DESC(buflen, "I/O buffer siz + + #ifdef CONFIG_USB_FILE_STORAGE_TEST + +-#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) +-#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) +-#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) ++#define transport_is_bbb() (mod_data.transport_type == US_PR_BULK) ++#define transport_is_cbi() (mod_data.transport_type == US_PR_CBI) ++#define protocol_is_scsi() (mod_data.protocol_type == US_SC_SCSI) + + #else + +@@ -2183,18 +2183,18 @@ static int send_status(struct fsg_dev *f + start_transfer(fsg, fsg->bulk_in, bh->inreq, + &bh->inreq_busy, &bh->state); + +- } else if (mod_data.transport_type == USB_PR_CB) { ++ } else if (mod_data.transport_type == US_PR_CB) { + + /* Control-Bulk transport has no status phase! */ + return 0; + +- } else { // USB_PR_CBI ++ } else { // US_PR_CBI + struct interrupt_data *buf = bh->buf; + + /* Store and send the Interrupt data. UFI sends the ASC + * and ASCQ bytes. Everything else sends a Type (which + * is always 0) and the status Value. */ +- if (mod_data.protocol_type == USB_SC_UFI) { ++ if (mod_data.protocol_type == US_SC_UFI) { + buf->bType = ASC(sd); + buf->bValue = ASCQ(sd); + } else { +@@ -2236,7 +2236,7 @@ static int check_command(struct fsg_dev + + /* There's some disagreement as to whether RBC pads commands or not. + * We'll play it safe and accept either form. */ +- else if (mod_data.protocol_type == USB_SC_RBC) { ++ else if (mod_data.protocol_type == US_SC_RBC) { + if (fsg->cmnd_size == 12) + cmnd_size = 12; + +@@ -2707,7 +2707,7 @@ static int get_next_command(struct fsg_d + rc = received_cbw(fsg, bh); + bh->state = BUF_STATE_EMPTY; + +- } else { // USB_PR_CB or USB_PR_CBI ++ } else { // US_PR_CB or US_PR_CBI + + /* Wait for the next command to arrive */ + while (fsg->cbbuf_cmnd_size == 0) { +@@ -3213,9 +3213,9 @@ static int __init check_parameters(struc + int gcnum; + + /* Store the default values */ +- mod_data.transport_type = USB_PR_BULK; ++ mod_data.transport_type = US_PR_BULK; + mod_data.transport_name = "Bulk-only"; +- mod_data.protocol_type = USB_SC_SCSI; ++ mod_data.protocol_type = US_SC_SCSI; + mod_data.protocol_name = "Transparent SCSI"; + + /* Some peripheral controllers are known not to be able to +@@ -3242,10 +3242,10 @@ static int __init check_parameters(struc + if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { + ; // Use default setting + } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { +- mod_data.transport_type = USB_PR_CB; ++ mod_data.transport_type = US_PR_CB; + mod_data.transport_name = "Control-Bulk"; + } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { +- mod_data.transport_type = USB_PR_CBI; ++ mod_data.transport_type = US_PR_CBI; + mod_data.transport_name = "Control-Bulk-Interrupt"; + } else { + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); +@@ -3253,28 +3253,28 @@ static int __init check_parameters(struc + } + + if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || +- prot == USB_SC_SCSI) { ++ prot == US_SC_SCSI) { + ; // Use default setting + } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || +- prot == USB_SC_RBC) { +- mod_data.protocol_type = USB_SC_RBC; ++ prot == US_SC_RBC) { ++ mod_data.protocol_type = US_SC_RBC; + mod_data.protocol_name = "RBC"; + } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || + strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || +- prot == USB_SC_8020) { +- mod_data.protocol_type = USB_SC_8020; ++ prot == US_SC_8020) { ++ mod_data.protocol_type = US_SC_8020; + mod_data.protocol_name = "8020i (ATAPI)"; + } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || +- prot == USB_SC_QIC) { +- mod_data.protocol_type = USB_SC_QIC; ++ prot == US_SC_QIC) { ++ mod_data.protocol_type = US_SC_QIC; + mod_data.protocol_name = "QIC-157"; + } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || +- prot == USB_SC_UFI) { +- mod_data.protocol_type = USB_SC_UFI; ++ prot == US_SC_UFI) { ++ mod_data.protocol_type = US_SC_UFI; + mod_data.protocol_name = "UFI"; + } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || +- prot == USB_SC_8070) { +- mod_data.protocol_type = USB_SC_8070; ++ prot == US_SC_8070) { ++ mod_data.protocol_type = US_SC_8070; + mod_data.protocol_name = "8070i"; + } else { + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); +@@ -3312,8 +3312,8 @@ static int __init check_parameters(struc + } + } + if (len > 126 || +- (mod_data.transport_type == USB_PR_BULK && len < 12) || +- (mod_data.transport_type != USB_PR_BULK && len > 12)) { ++ (mod_data.transport_type == US_PR_BULK && len < 12) || ++ (mod_data.transport_type != US_PR_BULK && len > 12)) { + WARNING(fsg, "Invalid serial string length!\n"); + goto no_serial; + } +--- a/drivers/usb/gadget/storage_common.c ++++ b/drivers/usb/gadget/storage_common.c +@@ -54,6 +54,7 @@ + + + #include <asm/unaligned.h> ++#include <linux/usb/storage.h> + + + /* +@@ -156,19 +157,6 @@ + #define TYPE_DISK 0x00 + #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 */ +- +-/* 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 */ +- + /* Bulk-only data structures */ + + /* Command Block Wrapper */ +@@ -407,8 +395,8 @@ fsg_intf_desc = { + + .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 = US_SC_SCSI, /* Adjusted during fsg_bind() */ ++ .bInterfaceProtocol = US_PR_BULK, /* Adjusted during fsg_bind() */ + .iInterface = FSG_STRING_INTERFACE, + }; + diff --git a/usb/usb-move-usb-storage-definitions-to-their-own-header-file.patch b/usb/usb-move-usb-storage-definitions-to-their-own-header-file.patch new file mode 100644 index 00000000000000..bb861ffaa4bd69 --- /dev/null +++ b/usb/usb-move-usb-storage-definitions-to-their-own-header-file.patch @@ -0,0 +1,117 @@ +From willy@linux.intel.com Tue Sep 28 18:52:20 2010 +From: Matthew Wilcox <willy@linux.intel.com> +Date: Tue, 28 Sep 2010 06:14:55 -0400 +Subject: USB: Move USB Storage definitions to their own header file +To: greg@kroah.com, linux-usb@vger.kernel.org, linux-scsi@vger.kernel.org, sarah.a.sharp@linux.intel.com +Cc: Matthew Wilcox <matthew.r.wilcox@intel.com>, Matthew Wilcox <willy@linux.intel.com> +Message-ID: <1285668896-6356-1-git-send-email-willy@linux.intel.com> + + +From: Matthew Wilcox <matthew.r.wilcox@intel.com> + +The libusual header file is hard to use from code that isn't part +of libusual. As the comment suggests, these definitions are moved to +their own header file, paralleling other USB classes. + +Signed-off-by: Matthew Wilcox <willy@linux.intel.com> +Cc: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + include/linux/usb/storage.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ + include/linux/usb_usual.h | 37 +------------------------------------ + 2 files changed, 45 insertions(+), 36 deletions(-) + +--- /dev/null ++++ b/include/linux/usb/storage.h +@@ -0,0 +1,44 @@ ++/* ++ * linux/usb/storage.h ++ * ++ * Copyright Matthew Wilcox for Intel Corp, 2010 ++ * ++ * This file contains definitions taken from the ++ * USB Mass Storage Class Specification Overview ++ * ++ * Distributed under the terms of the GNU GPL, version two. ++ */ ++ ++/* Storage subclass codes */ ++ ++#define US_SC_RBC 0x01 /* Typically, flash devices */ ++#define US_SC_8020 0x02 /* CD-ROM */ ++#define US_SC_QIC 0x03 /* QIC-157 Tapes */ ++#define US_SC_UFI 0x04 /* Floppy */ ++#define US_SC_8070 0x05 /* Removable media */ ++#define US_SC_SCSI 0x06 /* Transparent */ ++#define US_SC_LOCKABLE 0x07 /* Password-protected */ ++ ++#define US_SC_ISD200 0xf0 /* ISD200 ATA */ ++#define US_SC_CYP_ATACB 0xf1 /* Cypress ATACB */ ++#define US_SC_DEVICE 0xff /* Use device's value */ ++ ++/* Storage protocol codes */ ++ ++#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */ ++#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */ ++#define US_PR_BULK 0x50 /* bulk only */ ++#define US_PR_UAS 0x62 /* USB Attached SCSI */ ++ ++#define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */ ++#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ ++#define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */ ++#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ ++#define US_PR_FREECOM 0xf1 /* Freecom */ ++#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ ++#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ ++#define US_PR_ALAUDA 0xf4 /* Alauda chipsets */ ++#define US_PR_KARMA 0xf5 /* Rio Karma */ ++ ++#define US_PR_DEVICE 0xff /* Use device's value */ ++ +--- a/include/linux/usb_usual.h ++++ b/include/linux/usb_usual.h +@@ -74,42 +74,7 @@ enum { US_DO_ALL_FLAGS }; + #define USB_US_TYPE(flags) (((flags) >> 24) & 0xFF) + #define USB_US_ORIG_FLAGS(flags) ((flags) & 0x00FFFFFF) + +-/* +- * This is probably not the best place to keep these constants, conceptually. +- * But it's the only header included into all places which need them. +- */ +- +-/* Sub Classes */ +- +-#define US_SC_RBC 0x01 /* Typically, flash devices */ +-#define US_SC_8020 0x02 /* CD-ROM */ +-#define US_SC_QIC 0x03 /* QIC-157 Tapes */ +-#define US_SC_UFI 0x04 /* Floppy */ +-#define US_SC_8070 0x05 /* Removable media */ +-#define US_SC_SCSI 0x06 /* Transparent */ +-#define US_SC_LOCKABLE 0x07 /* Password-protected */ +- +-#define US_SC_ISD200 0xf0 /* ISD200 ATA */ +-#define US_SC_CYP_ATACB 0xf1 /* Cypress ATACB */ +-#define US_SC_DEVICE 0xff /* Use device's value */ +- +-/* Protocols */ +- +-#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */ +-#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */ +-#define US_PR_BULK 0x50 /* bulk only */ +- +-#define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */ +-#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ +-#define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */ +-#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ +-#define US_PR_FREECOM 0xf1 /* Freecom */ +-#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ +-#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ +-#define US_PR_ALAUDA 0xf4 /* Alauda chipsets */ +-#define US_PR_KARMA 0xf5 /* Rio Karma */ +- +-#define US_PR_DEVICE 0xff /* Use device's value */ ++#include <linux/usb/storage.h> + + /* + */ |
