aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/storage
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/Kconfig150
-rw-r--r--drivers/usb/storage/Makefile46
-rw-r--r--drivers/usb/storage/alauda.c1267
-rw-r--r--drivers/usb/storage/cypress_atacb.c290
-rw-r--r--drivers/usb/storage/datafab.c173
-rw-r--r--drivers/usb/storage/datafab.h40
-rw-r--r--drivers/usb/storage/debug.c39
-rw-r--r--drivers/usb/storage/debug.h26
-rw-r--r--drivers/usb/storage/dpcm.c89
-rw-r--r--drivers/usb/storage/ene_ub6250.c2420
-rw-r--r--drivers/usb/storage/freecom.c212
-rw-r--r--drivers/usb/storage/initializers.c37
-rw-r--r--drivers/usb/storage/initializers.h10
-rw-r--r--drivers/usb/storage/isd200.c598
-rw-r--r--drivers/usb/storage/jumpshot.c180
-rw-r--r--drivers/usb/storage/jumpshot.h39
-rw-r--r--drivers/usb/storage/karma.c236
-rw-r--r--drivers/usb/storage/onetouch.c180
-rw-r--r--drivers/usb/storage/onetouch.h9
-rw-r--r--drivers/usb/storage/option_ms.c171
-rw-r--r--drivers/usb/storage/option_ms.h4
-rw-r--r--drivers/usb/storage/protocol.c171
-rw-r--r--drivers/usb/storage/protocol.h21
-rw-r--r--drivers/usb/storage/realtek_cr.c1071
-rw-r--r--drivers/usb/storage/scsiglue.c345
-rw-r--r--drivers/usb/storage/scsiglue.h2
-rw-r--r--drivers/usb/storage/sddr09.c549
-rw-r--r--drivers/usb/storage/sddr09.h48
-rw-r--r--drivers/usb/storage/sddr55.c200
-rw-r--r--drivers/usb/storage/shuttle_usbat.c491
-rw-r--r--drivers/usb/storage/shuttle_usbat.h123
-rw-r--r--drivers/usb/storage/sierra_ms.c199
-rw-r--r--drivers/usb/storage/sierra_ms.h4
-rw-r--r--drivers/usb/storage/transport.c776
-rw-r--r--drivers/usb/storage/transport.h76
-rw-r--r--drivers/usb/storage/uas-detect.h96
-rw-r--r--drivers/usb/storage/uas.c1261
-rw-r--r--drivers/usb/storage/unusual_alauda.h (renamed from drivers/usb/storage/freecom.h)31
-rw-r--r--drivers/usb/storage/unusual_cypress.h39
-rw-r--r--drivers/usb/storage/unusual_datafab.h98
-rw-r--r--drivers/usb/storage/unusual_devs.h1954
-rw-r--r--drivers/usb/storage/unusual_ene_ub6250.h (renamed from drivers/usb/storage/isd200.h)21
-rw-r--r--drivers/usb/storage/unusual_freecom.h (renamed from drivers/usb/storage/sddr55.h)24
-rw-r--r--drivers/usb/storage/unusual_isd200.h57
-rw-r--r--drivers/usb/storage/unusual_jumpshot.h (renamed from drivers/usb/storage/dpcm.h)25
-rw-r--r--drivers/usb/storage/unusual_karma.h26
-rw-r--r--drivers/usb/storage/unusual_onetouch.h36
-rw-r--r--drivers/usb/storage/unusual_realtek.h41
-rw-r--r--drivers/usb/storage/unusual_sddr09.h56
-rw-r--r--drivers/usb/storage/unusual_sddr55.h44
-rw-r--r--drivers/usb/storage/unusual_uas.h52
-rw-r--r--drivers/usb/storage/unusual_usbat.h43
-rw-r--r--drivers/usb/storage/usb.c1139
-rw-r--r--drivers/usb/storage/usb.h115
-rw-r--r--drivers/usb/storage/usual-tables.c123
55 files changed, 12477 insertions, 3096 deletions
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 1a9679f76f5..13b5bfbaf95 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -2,14 +2,12 @@
# USB Storage driver configuration
#
-comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'"
-comment "may also be needed; see USB_STORAGE Help for more information"
- depends on USB
+comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may"
+comment "also be needed; see USB_STORAGE Help for more info"
config USB_STORAGE
tristate "USB Mass Storage support"
- depends on USB
- select SCSI
+ depends on SCSI
---help---
Say Y here if you want to connect USB mass storage devices to your
computer's USB port. This is the driver you need for USB
@@ -18,9 +16,11 @@ config USB_STORAGE
similar devices. This driver may also be used for some cameras
and card readers.
- This option 'selects' (turns on, enables) 'SCSI', but you
+ This option depends on 'SCSI' support being enabled, but you
probably also need 'SCSI device support: SCSI disk support'
- (BLK_DEV_SD) for most USB storage devices.
+ (BLK_DEV_SD) for most USB storage devices. Some devices also
+ will require 'Probe all LUNs on each SCSI device'
+ (SCSI_MULTI_LUN).
To compile this driver as a module, choose M here: the
module will be called usb-storage.
@@ -32,23 +32,41 @@ config USB_STORAGE_DEBUG
Say Y here in order to have the USB Mass Storage code generate
verbose debugging messages.
+config USB_STORAGE_REALTEK
+ tristate "Realtek Card Reader support"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the power-saving function
+ for Realtek RTS51xx USB card readers.
+
+ If this driver is compiled as a module, it will be named ums-realtek.
+
+config REALTEK_AUTOPM
+ bool "Realtek Card Reader autosuspend support"
+ depends on USB_STORAGE_REALTEK && PM_RUNTIME
+ default y
+
config USB_STORAGE_DATAFAB
- bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ tristate "Datafab Compact Flash Reader support"
+ depends on USB_STORAGE
help
Support for certain Datafab CompactFlash readers.
- Datafab has a web page at <http://www.datafabusa.com/>.
+ Datafab has a web page at <http://www.datafab.com/>.
+
+ If this driver is compiled as a module, it will be named ums-datafab.
config USB_STORAGE_FREECOM
- bool "Freecom USB/ATAPI Bridge support"
+ tristate "Freecom USB/ATAPI Bridge support"
depends on USB_STORAGE
help
Support for the Freecom USB to IDE/ATAPI adaptor.
Freecom has a web page at <http://www.freecom.de/>.
+ If this driver is compiled as a module, it will be named ums-freecom.
+
config USB_STORAGE_ISD200
- bool "ISD-200 USB/ATA Bridge support"
- depends on USB_STORAGE && BLK_DEV_IDE
+ tristate "ISD-200 USB/ATA Bridge support"
+ depends on USB_STORAGE
---help---
Say Y here if you want to use USB Mass Store devices based
on the In-Systems Design ISD-200 USB/ATA bridge.
@@ -62,16 +80,11 @@ config USB_STORAGE_ISD200
- CyQ've CQ8060A CDRW drive
- Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
-config USB_STORAGE_DPCM
- bool "Microtech/ZiO! CompactFlash/SmartMedia support"
- depends on USB_STORAGE
- help
- Say Y here to support the Microtech/ZiO! CompactFlash reader.
- There is a web page at <http://www.ziocorp.com/products/>.
+ If this driver is compiled as a module, it will be named ums-isd200.
config USB_STORAGE_USBAT
- bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ tristate "USBAT/USBAT02-based storage support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support storage devices
based on the SCM/Shuttle USBAT/USBAT02 processors.
@@ -90,32 +103,52 @@ config USB_STORAGE_USBAT
- RCA LYRA MP3 portable
- Sandisk ImageMate SDDR-05b
+ If this driver is compiled as a module, it will be named ums-usbat.
+
config USB_STORAGE_SDDR09
- bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
- Also works for the Microtech Zio! SmartMedia reader.
+ Also works for the Microtech Zio! CompactFlash/SmartMedia reader.
+
+ If this driver is compiled as a module, it will be named ums-sddr09.
config USB_STORAGE_SDDR55
- bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ tristate "SanDisk SDDR-55 SmartMedia support"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-55
SmartMedia reader in the USB Mass Storage driver.
+ If this driver is compiled as a module, it will be named ums-sddr55.
+
config USB_STORAGE_JUMPSHOT
- bool "Lexar Jumpshot Compact Flash Reader (EXPERIMENTAL)"
- depends on USB_STORAGE && EXPERIMENTAL
+ tristate "Lexar Jumpshot Compact Flash Reader"
+ depends on USB_STORAGE
help
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.
+ If this driver is compiled as a module, it will be named ums-jumpshot.
+
+config USB_STORAGE_ALAUDA
+ tristate "Olympus MAUSB-10/Fuji DPC-R1 support"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the Olympus MAUSB-10
+ and Fujifilm DPC-R1 USB Card reader/writer devices.
+
+ These devices are based on the Alauda chip and support both
+ XD and SmartMedia cards.
+
+ If this driver is compiled as a module, it will be named ums-alauda.
config USB_STORAGE_ONETOUCH
- bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
- depends on USB_STORAGE && INPUT_EVDEV && EXPERIMENTAL
+ tristate "Support OneTouch Button on Maxtor Hard Drives"
+ depends on USB_STORAGE
+ depends on INPUT=y || INPUT=USB_STORAGE
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
@@ -124,3 +157,60 @@ config USB_STORAGE_ONETOUCH
hard drive's as an input device. An action can be associated with
this input in any keybinding software. (e.g. gnome's keyboard short-
cuts)
+
+ If this driver is compiled as a module, it will be named ums-onetouch.
+
+config USB_STORAGE_KARMA
+ tristate "Support for Rio Karma music player"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the Rio Karma
+ USB interface.
+
+ This code places the Rio Karma into mass storage mode, enabling
+ it to be mounted as an ordinary filesystem. Performing an eject
+ on the resulting scsi device node returns the Karma to normal
+ operation.
+
+ If this driver is compiled as a module, it will be named ums-karma.
+
+config USB_STORAGE_CYPRESS_ATACB
+ tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB"
+ depends on USB_STORAGE
+ ---help---
+ Say Y here if you want to use SAT (ata pass through) on devices based
+ on the Cypress USB/ATA bridge supporting ATACB. This will allow you
+ to use tools to tune and monitor your drive (like hdparm or smartctl).
+
+ If you say no here your device will still work with the standard usb
+ mass storage class.
+
+ If this driver is compiled as a module, it will be named ums-cypress.
+
+config USB_STORAGE_ENE_UB6250
+ tristate "USB ENE card reader support"
+ depends on SCSI
+ depends on USB_STORAGE
+ ---help---
+ Say Y here if you wish to control a ENE SD/MS Card reader.
+ To use SM card, please build driver/staging/keucr/keucr.ko
+
+ This option depends on 'SCSI' support being enabled, but you
+ probably also need 'SCSI device support: SCSI disk support'
+ (BLK_DEV_SD) for most USB storage devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ums-eneub6250.
+
+config USB_UAS
+ tristate "USB Attached SCSI"
+ depends on SCSI && USB_STORAGE
+ 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.
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 44ab8f9978f..4cd55481b30 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -5,20 +5,40 @@
# Rewritten to use lists instead of if-statements.
#
-EXTRA_CFLAGS := -Idrivers/scsi
+ccflags-y := -Idrivers/scsi
+obj-$(CONFIG_USB_UAS) += uas.o
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT) += shuttle_usbat.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55) += sddr55.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
+usb-storage-y := scsiglue.o protocol.o transport.o usb.o
+usb-storage-y += initializers.o sierra_ms.o option_ms.o
+usb-storage-y += usual-tables.o
+usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
-usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
- initializers.o $(usb-storage-obj-y)
+obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o
+obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o
+obj-$(CONFIG_USB_STORAGE_DATAFAB) += ums-datafab.o
+obj-$(CONFIG_USB_STORAGE_ENE_UB6250) += ums-eneub6250.o
+obj-$(CONFIG_USB_STORAGE_FREECOM) += ums-freecom.o
+obj-$(CONFIG_USB_STORAGE_ISD200) += ums-isd200.o
+obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += ums-jumpshot.o
+obj-$(CONFIG_USB_STORAGE_KARMA) += ums-karma.o
+obj-$(CONFIG_USB_STORAGE_ONETOUCH) += ums-onetouch.o
+obj-$(CONFIG_USB_STORAGE_REALTEK) += ums-realtek.o
+obj-$(CONFIG_USB_STORAGE_SDDR09) += ums-sddr09.o
+obj-$(CONFIG_USB_STORAGE_SDDR55) += ums-sddr55.o
+obj-$(CONFIG_USB_STORAGE_USBAT) += ums-usbat.o
+
+ums-alauda-y := alauda.o
+ums-cypress-y := cypress_atacb.o
+ums-datafab-y := datafab.o
+ums-eneub6250-y := ene_ub6250.o
+ums-freecom-y := freecom.o
+ums-isd200-y := isd200.o
+ums-jumpshot-y := jumpshot.o
+ums-karma-y := karma.o
+ums-onetouch-y := onetouch.o
+ums-realtek-y := realtek_cr.o
+ums-sddr09-y := sddr09.o
+ums-sddr55-y := sddr55.o
+ums-usbat-y := shuttle_usbat.o
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
new file mode 100644
index 00000000000..6636a583da1
--- /dev/null
+++ b/drivers/usb/storage/alauda.c
@@ -0,0 +1,1267 @@
+/*
+ * Driver for Alauda-based card readers
+ *
+ * Current development and maintenance by:
+ * (c) 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * The 'Alauda' is a chip manufacturered by RATOC for OEM use.
+ *
+ * Alauda implements a vendor-specific command set to access two media reader
+ * ports (XD, SmartMedia). This driver converts SCSI commands to the commands
+ * which are accepted by these devices.
+ *
+ * The driver was developed through reverse-engineering, with the help of the
+ * sddr09 driver which has many similarities, and with some help from the
+ * (very old) vendor-supplied GPL sma03 driver.
+ *
+ * For protocol info, see http://alauda.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+
+MODULE_DESCRIPTION("Driver for Alauda-based card readers");
+MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * Status bytes
+ */
+#define ALAUDA_STATUS_ERROR 0x01
+#define ALAUDA_STATUS_READY 0x40
+
+/*
+ * Control opcodes (for request field)
+ */
+#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
+#define ALAUDA_GET_SM_MEDIA_STATUS 0x98
+#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
+#define ALAUDA_ACK_SM_MEDIA_CHANGE 0x9a
+#define ALAUDA_GET_XD_MEDIA_SIG 0x86
+#define ALAUDA_GET_SM_MEDIA_SIG 0x96
+
+/*
+ * Bulk command identity (byte 0)
+ */
+#define ALAUDA_BULK_CMD 0x40
+
+/*
+ * Bulk opcodes (byte 1)
+ */
+#define ALAUDA_BULK_GET_REDU_DATA 0x85
+#define ALAUDA_BULK_READ_BLOCK 0x94
+#define ALAUDA_BULK_ERASE_BLOCK 0xa3
+#define ALAUDA_BULK_WRITE_BLOCK 0xb4
+#define ALAUDA_BULK_GET_STATUS2 0xb7
+#define ALAUDA_BULK_RESET_MEDIA 0xe0
+
+/*
+ * Port to operate on (byte 8)
+ */
+#define ALAUDA_PORT_XD 0x00
+#define ALAUDA_PORT_SM 0x01
+
+/*
+ * LBA and PBA are unsigned ints. Special values.
+ */
+#define UNDEF 0xffff
+#define SPARE 0xfffe
+#define UNUSABLE 0xfffd
+
+struct alauda_media_info {
+ unsigned long capacity; /* total media size in bytes */
+ unsigned int pagesize; /* page size in bytes */
+ unsigned int blocksize; /* number of pages per block */
+ unsigned int uzonesize; /* number of usable blocks per zone */
+ unsigned int zonesize; /* number of blocks per zone */
+ unsigned int blockmask; /* mask to get page from address */
+
+ unsigned char pageshift;
+ unsigned char blockshift;
+ unsigned char zoneshift;
+
+ u16 **lba_to_pba; /* logical to physical block map */
+ u16 **pba_to_lba; /* physical to logical block map */
+};
+
+struct alauda_info {
+ struct alauda_media_info port[2];
+ int wr_ep; /* endpoint to write data out of */
+
+ unsigned char sense_key;
+ unsigned long sense_asc; /* additional sense code */
+ unsigned long sense_ascq; /* additional sense code qualifier */
+};
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+#define MEDIA_PORT(us) us->srb->device->lun
+#define MEDIA_INFO(us) ((struct alauda_info *)us->extra)->port[MEDIA_PORT(us)]
+
+#define PBA_LO(pba) ((pba & 0xF) << 5)
+#define PBA_HI(pba) (pba >> 3)
+#define PBA_ZONE(pba) (pba >> 11)
+
+static int init_alauda(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id alauda_usb_ids[] = {
+# include "unusual_alauda.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, alauda_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev alauda_unusual_dev_list[] = {
+# include "unusual_alauda.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * Media handling
+ */
+
+struct alauda_card_info {
+ unsigned char id; /* id byte */
+ unsigned char chipshift; /* 1<<cs bytes total capacity */
+ unsigned char pageshift; /* 1<<ps bytes in a page */
+ unsigned char blockshift; /* 1<<bs pages per block */
+ unsigned char zoneshift; /* 1<<zs blocks per zone */
+};
+
+static struct alauda_card_info alauda_card_ids[] = {
+ /* NAND flash */
+ { 0x6e, 20, 8, 4, 8}, /* 1 MB */
+ { 0xe8, 20, 8, 4, 8}, /* 1 MB */
+ { 0xec, 20, 8, 4, 8}, /* 1 MB */
+ { 0x64, 21, 8, 4, 9}, /* 2 MB */
+ { 0xea, 21, 8, 4, 9}, /* 2 MB */
+ { 0x6b, 22, 9, 4, 9}, /* 4 MB */
+ { 0xe3, 22, 9, 4, 9}, /* 4 MB */
+ { 0xe5, 22, 9, 4, 9}, /* 4 MB */
+ { 0xe6, 23, 9, 4, 10}, /* 8 MB */
+ { 0x73, 24, 9, 5, 10}, /* 16 MB */
+ { 0x75, 25, 9, 5, 10}, /* 32 MB */
+ { 0x76, 26, 9, 5, 10}, /* 64 MB */
+ { 0x79, 27, 9, 5, 10}, /* 128 MB */
+ { 0x71, 28, 9, 5, 10}, /* 256 MB */
+
+ /* MASK ROM */
+ { 0x5d, 21, 9, 4, 8}, /* 2 MB */
+ { 0xd5, 22, 9, 4, 9}, /* 4 MB */
+ { 0xd6, 23, 9, 4, 10}, /* 8 MB */
+ { 0x57, 24, 9, 4, 11}, /* 16 MB */
+ { 0x58, 25, 9, 4, 12}, /* 32 MB */
+ { 0,}
+};
+
+static struct alauda_card_info *alauda_card_find_id(unsigned char id) {
+ int i;
+
+ for (i = 0; alauda_card_ids[i].id != 0; i++)
+ if (alauda_card_ids[i].id == id)
+ return &(alauda_card_ids[i]);
+ return NULL;
+}
+
+/*
+ * ECC computation.
+ */
+
+static unsigned char parity[256];
+static unsigned char ecc2[256];
+
+static void nand_init_ecc(void) {
+ int i, j, a;
+
+ parity[0] = 0;
+ for (i = 1; i < 256; i++)
+ parity[i] = (parity[i&(i-1)] ^ 1);
+
+ for (i = 0; i < 256; i++) {
+ a = 0;
+ for (j = 0; j < 8; j++) {
+ if (i & (1<<j)) {
+ if ((j & 1) == 0)
+ a ^= 0x04;
+ if ((j & 2) == 0)
+ a ^= 0x10;
+ if ((j & 4) == 0)
+ a ^= 0x40;
+ }
+ }
+ ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
+ }
+}
+
+/* compute 3-byte ecc on 256 bytes */
+static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
+ int i, j, a;
+ unsigned char par = 0, bit, bits[8] = {0};
+
+ /* collect 16 checksum bits */
+ for (i = 0; i < 256; i++) {
+ par ^= data[i];
+ bit = parity[data[i]];
+ for (j = 0; j < 8; j++)
+ if ((i & (1<<j)) == 0)
+ bits[j] ^= bit;
+ }
+
+ /* put 4+4+4 = 12 bits in the ecc */
+ a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
+ ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+ a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
+ ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+ ecc[2] = ecc2[par];
+}
+
+static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
+ return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
+}
+
+static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
+ memcpy(data, ecc, 3);
+}
+
+/*
+ * Alauda driver
+ */
+
+/*
+ * Forget our PBA <---> LBA mappings for a particular port
+ */
+static void alauda_free_maps (struct alauda_media_info *media_info)
+{
+ unsigned int shift = media_info->zoneshift
+ + media_info->blockshift + media_info->pageshift;
+ unsigned int num_zones = media_info->capacity >> shift;
+ unsigned int i;
+
+ if (media_info->lba_to_pba != NULL)
+ for (i = 0; i < num_zones; i++) {
+ kfree(media_info->lba_to_pba[i]);
+ media_info->lba_to_pba[i] = NULL;
+ }
+
+ if (media_info->pba_to_lba != NULL)
+ for (i = 0; i < num_zones; i++) {
+ kfree(media_info->pba_to_lba[i]);
+ media_info->pba_to_lba[i] = NULL;
+ }
+}
+
+/*
+ * Returns 2 bytes of status data
+ * The first byte describes media status, and second byte describes door status
+ */
+static int alauda_get_media_status(struct us_data *us, unsigned char *data)
+{
+ int rc;
+ unsigned char command;
+
+ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+ command = ALAUDA_GET_XD_MEDIA_STATUS;
+ else
+ command = ALAUDA_GET_SM_MEDIA_STATUS;
+
+ rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+ command, 0xc0, 0, 1, data, 2);
+
+ usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
+
+ return rc;
+}
+
+/*
+ * Clears the "media was changed" bit so that we know when it changes again
+ * in the future.
+ */
+static int alauda_ack_media(struct us_data *us)
+{
+ unsigned char command;
+
+ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+ command = ALAUDA_ACK_XD_MEDIA_CHANGE;
+ else
+ command = ALAUDA_ACK_SM_MEDIA_CHANGE;
+
+ return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+ command, 0x40, 0, 1, NULL, 0);
+}
+
+/*
+ * Retrieves a 4-byte media signature, which indicates manufacturer, capacity,
+ * and some other details.
+ */
+static int alauda_get_media_signature(struct us_data *us, unsigned char *data)
+{
+ unsigned char command;
+
+ if (MEDIA_PORT(us) == ALAUDA_PORT_XD)
+ command = ALAUDA_GET_XD_MEDIA_SIG;
+ else
+ command = ALAUDA_GET_SM_MEDIA_SIG;
+
+ return usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+ command, 0xc0, 0, 0, data, 4);
+}
+
+/*
+ * Resets the media status (but not the whole device?)
+ */
+static int alauda_reset_media(struct us_data *us)
+{
+ unsigned char *command = us->iobuf;
+
+ memset(command, 0, 9);
+ command[0] = ALAUDA_BULK_CMD;
+ command[1] = ALAUDA_BULK_RESET_MEDIA;
+ command[8] = MEDIA_PORT(us);
+
+ return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+}
+
+/*
+ * Examines the media and deduces capacity, etc.
+ */
+static int alauda_init_media(struct us_data *us)
+{
+ unsigned char *data = us->iobuf;
+ int ready = 0;
+ struct alauda_card_info *media_info;
+ unsigned int num_zones;
+
+ while (ready == 0) {
+ msleep(20);
+
+ if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (data[0] & 0x10)
+ ready = 1;
+ }
+
+ usb_stor_dbg(us, "We are ready for action!\n");
+
+ if (alauda_ack_media(us) != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ msleep(10);
+
+ if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (data[0] != 0x14) {
+ usb_stor_dbg(us, "Media not ready after ack\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ usb_stor_dbg(us, "Media signature: %02X %02X %02X %02X\n",
+ data[0], data[1], data[2], data[3]);
+ media_info = alauda_card_find_id(data[1]);
+ if (media_info == NULL) {
+ printk(KERN_WARNING
+ "alauda_init_media: Unrecognised media signature: "
+ "%02X %02X %02X %02X\n",
+ data[0], data[1], data[2], data[3]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ MEDIA_INFO(us).capacity = 1 << media_info->chipshift;
+ usb_stor_dbg(us, "Found media with capacity: %ldMB\n",
+ MEDIA_INFO(us).capacity >> 20);
+
+ MEDIA_INFO(us).pageshift = media_info->pageshift;
+ MEDIA_INFO(us).blockshift = media_info->blockshift;
+ MEDIA_INFO(us).zoneshift = media_info->zoneshift;
+
+ MEDIA_INFO(us).pagesize = 1 << media_info->pageshift;
+ MEDIA_INFO(us).blocksize = 1 << media_info->blockshift;
+ MEDIA_INFO(us).zonesize = 1 << media_info->zoneshift;
+
+ MEDIA_INFO(us).uzonesize = ((1 << media_info->zoneshift) / 128) * 125;
+ MEDIA_INFO(us).blockmask = MEDIA_INFO(us).blocksize - 1;
+
+ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+ + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
+ MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
+ MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO);
+
+ if (alauda_reset_media(us) != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Examines the media status and does the right thing when the media has gone,
+ * appeared, or changed.
+ */
+static int alauda_check_media(struct us_data *us)
+{
+ struct alauda_info *info = (struct alauda_info *) us->extra;
+ unsigned char status[2];
+ int rc;
+
+ rc = alauda_get_media_status(us, status);
+
+ /* Check for no media or door open */
+ if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
+ || ((status[1] & 0x01) == 0)) {
+ usb_stor_dbg(us, "No media, or door open\n");
+ alauda_free_maps(&MEDIA_INFO(us));
+ info->sense_key = 0x02;
+ info->sense_asc = 0x3A;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Check for media change */
+ if (status[0] & 0x08) {
+ usb_stor_dbg(us, "Media change detected\n");
+ alauda_free_maps(&MEDIA_INFO(us));
+ alauda_init_media(us);
+
+ info->sense_key = UNIT_ATTENTION;
+ info->sense_asc = 0x28;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Checks the status from the 2nd status register
+ * Returns 3 bytes of status data, only the first is known
+ */
+static int alauda_check_status2(struct us_data *us)
+{
+ int rc;
+ unsigned char command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_GET_STATUS2,
+ 0, 0, 0, 0, 3, 0, MEDIA_PORT(us)
+ };
+ unsigned char data[3];
+
+ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data, 3, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ usb_stor_dbg(us, "%02X %02X %02X\n", data[0], data[1], data[2]);
+ if (data[0] & ALAUDA_STATUS_ERROR)
+ return USB_STOR_XFER_ERROR;
+
+ return USB_STOR_XFER_GOOD;
+}
+
+/*
+ * Gets the redundancy data for the first page of a PBA
+ * Returns 16 bytes.
+ */
+static int alauda_get_redu_data(struct us_data *us, u16 pba, unsigned char *data)
+{
+ int rc;
+ unsigned char command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_GET_REDU_DATA,
+ PBA_HI(pba), PBA_ZONE(pba), 0, PBA_LO(pba), 0, 0, MEDIA_PORT(us)
+ };
+
+ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data, 16, NULL);
+}
+
+/*
+ * Finds the first unused PBA in a zone
+ * Returns the absolute PBA of an unused PBA, or 0 if none found.
+ */
+static u16 alauda_find_unused_pba(struct alauda_media_info *info,
+ unsigned int zone)
+{
+ u16 *pba_to_lba = info->pba_to_lba[zone];
+ unsigned int i;
+
+ for (i = 0; i < info->zonesize; i++)
+ if (pba_to_lba[i] == UNDEF)
+ return (zone << info->zoneshift) + i;
+
+ return 0;
+}
+
+/*
+ * Reads the redundancy data for all PBA's in a zone
+ * Produces lba <--> pba mappings
+ */
+static int alauda_read_map(struct us_data *us, unsigned int zone)
+{
+ unsigned char *data = us->iobuf;
+ int result;
+ int i, j;
+ unsigned int zonesize = MEDIA_INFO(us).zonesize;
+ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+ unsigned int lba_offset, lba_real, blocknum;
+ unsigned int zone_base_lba = zone * uzonesize;
+ unsigned int zone_base_pba = zone * zonesize;
+ u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
+ u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_NOIO);
+ if (lba_to_pba == NULL || pba_to_lba == NULL) {
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto error;
+ }
+
+ usb_stor_dbg(us, "Mapping blocks for zone %d\n", zone);
+
+ /* 1024 PBA's per zone */
+ for (i = 0; i < zonesize; i++)
+ lba_to_pba[i] = pba_to_lba[i] = UNDEF;
+
+ for (i = 0; i < zonesize; i++) {
+ blocknum = zone_base_pba + i;
+
+ result = alauda_get_redu_data(us, blocknum, data);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto error;
+ }
+
+ /* special PBAs have control field 0^16 */
+ for (j = 0; j < 16; j++)
+ if (data[j] != 0)
+ goto nonz;
+ pba_to_lba[i] = UNUSABLE;
+ usb_stor_dbg(us, "PBA %d has no logical mapping\n", blocknum);
+ continue;
+
+ nonz:
+ /* unwritten PBAs have control field FF^16 */
+ for (j = 0; j < 16; j++)
+ if (data[j] != 0xff)
+ goto nonff;
+ continue;
+
+ nonff:
+ /* normal PBAs start with six FFs */
+ if (j < 6) {
+ usb_stor_dbg(us, "PBA %d has no logical mapping: reserved area = %02X%02X%02X%02X data status %02X block status %02X\n",
+ blocknum,
+ data[0], data[1], data[2], data[3],
+ data[4], data[5]);
+ pba_to_lba[i] = UNUSABLE;
+ continue;
+ }
+
+ if ((data[6] >> 4) != 0x01) {
+ usb_stor_dbg(us, "PBA %d has invalid address field %02X%02X/%02X%02X\n",
+ blocknum, data[6], data[7],
+ data[11], data[12]);
+ pba_to_lba[i] = UNUSABLE;
+ continue;
+ }
+
+ /* check even parity */
+ if (parity[data[6] ^ data[7]]) {
+ printk(KERN_WARNING
+ "alauda_read_map: Bad parity in LBA for block %d"
+ " (%02X %02X)\n", i, data[6], data[7]);
+ pba_to_lba[i] = UNUSABLE;
+ continue;
+ }
+
+ lba_offset = short_pack(data[7], data[6]);
+ lba_offset = (lba_offset & 0x07FF) >> 1;
+ lba_real = lba_offset + zone_base_lba;
+
+ /*
+ * Every 1024 physical blocks ("zone"), the LBA numbers
+ * go back to zero, but are within a higher block of LBA's.
+ * Also, there is a maximum of 1000 LBA's per zone.
+ * In other words, in PBA 1024-2047 you will find LBA 0-999
+ * which are really LBA 1000-1999. This allows for 24 bad
+ * or special physical blocks per zone.
+ */
+
+ if (lba_offset >= uzonesize) {
+ printk(KERN_WARNING
+ "alauda_read_map: Bad low LBA %d for block %d\n",
+ lba_real, blocknum);
+ continue;
+ }
+
+ if (lba_to_pba[lba_offset] != UNDEF) {
+ printk(KERN_WARNING
+ "alauda_read_map: "
+ "LBA %d seen for PBA %d and %d\n",
+ lba_real, lba_to_pba[lba_offset], blocknum);
+ continue;
+ }
+
+ pba_to_lba[i] = lba_real;
+ lba_to_pba[lba_offset] = blocknum;
+ continue;
+ }
+
+ MEDIA_INFO(us).lba_to_pba[zone] = lba_to_pba;
+ MEDIA_INFO(us).pba_to_lba[zone] = pba_to_lba;
+ result = 0;
+ goto out;
+
+error:
+ kfree(lba_to_pba);
+ kfree(pba_to_lba);
+out:
+ return result;
+}
+
+/*
+ * Checks to see whether we have already mapped a certain zone
+ * If we haven't, the map is generated
+ */
+static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone)
+{
+ if (MEDIA_INFO(us).lba_to_pba[zone] == NULL
+ || MEDIA_INFO(us).pba_to_lba[zone] == NULL)
+ alauda_read_map(us, zone);
+}
+
+/*
+ * Erases an entire block
+ */
+static int alauda_erase_block(struct us_data *us, u16 pba)
+{
+ int rc;
+ unsigned char command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us)
+ };
+ unsigned char buf[2];
+
+ usb_stor_dbg(us, "Erasing PBA %d\n", pba);
+
+ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ buf, 2, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ usb_stor_dbg(us, "Erase result: %02X %02X\n", buf[0], buf[1]);
+ return rc;
+}
+
+/*
+ * Reads data from a certain offset page inside a PBA, including interleaved
+ * redundancy data. Returns (pagesize+64)*pages bytes in data.
+ */
+static int alauda_read_block_raw(struct us_data *us, u16 pba,
+ unsigned int page, unsigned int pages, unsigned char *data)
+{
+ int rc;
+ unsigned char command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)
+ };
+
+ usb_stor_dbg(us, "pba %d page %d count %d\n", pba, page, pages);
+
+ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data, (MEDIA_INFO(us).pagesize + 64) * pages, NULL);
+}
+
+/*
+ * Reads data from a certain offset page inside a PBA, excluding redundancy
+ * data. Returns pagesize*pages bytes in data. Note that data must be big enough
+ * to hold (pagesize+64)*pages bytes of data, but you can ignore those 'extra'
+ * trailing bytes outside this function.
+ */
+static int alauda_read_block(struct us_data *us, u16 pba,
+ unsigned int page, unsigned int pages, unsigned char *data)
+{
+ int i, rc;
+ unsigned int pagesize = MEDIA_INFO(us).pagesize;
+
+ rc = alauda_read_block_raw(us, pba, page, pages, data);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ /* Cut out the redundancy data */
+ for (i = 0; i < pages; i++) {
+ int dest_offset = i * pagesize;
+ int src_offset = i * (pagesize + 64);
+ memmove(data + dest_offset, data + src_offset, pagesize);
+ }
+
+ return rc;
+}
+
+/*
+ * Writes an entire block of data and checks status after write.
+ * Redundancy data must be already included in data. Data should be
+ * (pagesize+64)*blocksize bytes in length.
+ */
+static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data)
+{
+ int rc;
+ struct alauda_info *info = (struct alauda_info *) us->extra;
+ unsigned char command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)
+ };
+
+ usb_stor_dbg(us, "pba %d\n", pba);
+
+ rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ command, 9, NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ rc = usb_stor_bulk_transfer_buf(us, info->wr_ep, data,
+ (MEDIA_INFO(us).pagesize + 64) * MEDIA_INFO(us).blocksize,
+ NULL);
+ if (rc != USB_STOR_XFER_GOOD)
+ return rc;
+
+ return alauda_check_status2(us);
+}
+
+/*
+ * Write some data to a specific LBA.
+ */
+static int alauda_write_lba(struct us_data *us, u16 lba,
+ unsigned int page, unsigned int pages,
+ unsigned char *ptr, unsigned char *blockbuffer)
+{
+ u16 pba, lbap, new_pba;
+ unsigned char *bptr, *cptr, *xptr;
+ unsigned char ecc[3];
+ int i, result;
+ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+ unsigned int zonesize = MEDIA_INFO(us).zonesize;
+ unsigned int pagesize = MEDIA_INFO(us).pagesize;
+ unsigned int blocksize = MEDIA_INFO(us).blocksize;
+ unsigned int lba_offset = lba % uzonesize;
+ unsigned int new_pba_offset;
+ unsigned int zone = lba / uzonesize;
+
+ alauda_ensure_map_for_zone(us, zone);
+
+ pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
+ if (pba == 1) {
+ /* Maybe it is impossible to write to PBA 1.
+ Fake success, but don't do anything. */
+ printk(KERN_WARNING
+ "alauda_write_lba: avoid writing to pba 1\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone);
+ if (!new_pba) {
+ printk(KERN_WARNING
+ "alauda_write_lba: Out of unused blocks\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* read old contents */
+ if (pba != UNDEF) {
+ result = alauda_read_block_raw(us, pba, 0,
+ blocksize, blockbuffer);
+ if (result != USB_STOR_XFER_GOOD)
+ return result;
+ } else {
+ memset(blockbuffer, 0, blocksize * (pagesize + 64));
+ }
+
+ lbap = (lba_offset << 1) | 0x1000;
+ if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
+ lbap ^= 1;
+
+ /* check old contents and fill lba */
+ for (i = 0; i < blocksize; i++) {
+ bptr = blockbuffer + (i * (pagesize + 64));
+ cptr = bptr + pagesize;
+ nand_compute_ecc(bptr, ecc);
+ if (!nand_compare_ecc(cptr+13, ecc)) {
+ usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+ i, pba);
+ nand_store_ecc(cptr+13, ecc);
+ }
+ nand_compute_ecc(bptr + (pagesize / 2), ecc);
+ if (!nand_compare_ecc(cptr+8, ecc)) {
+ usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+ i, pba);
+ nand_store_ecc(cptr+8, ecc);
+ }
+ cptr[6] = cptr[11] = MSB_of(lbap);
+ cptr[7] = cptr[12] = LSB_of(lbap);
+ }
+
+ /* copy in new stuff and compute ECC */
+ xptr = ptr;
+ for (i = page; i < page+pages; i++) {
+ bptr = blockbuffer + (i * (pagesize + 64));
+ cptr = bptr + pagesize;
+ memcpy(bptr, xptr, pagesize);
+ xptr += pagesize;
+ nand_compute_ecc(bptr, ecc);
+ nand_store_ecc(cptr+13, ecc);
+ nand_compute_ecc(bptr + (pagesize / 2), ecc);
+ nand_store_ecc(cptr+8, ecc);
+ }
+
+ result = alauda_write_block(us, new_pba, blockbuffer);
+ if (result != USB_STOR_XFER_GOOD)
+ return result;
+
+ new_pba_offset = new_pba - (zone * zonesize);
+ MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba;
+ MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba;
+ usb_stor_dbg(us, "Remapped LBA %d to PBA %d\n", lba, new_pba);
+
+ if (pba != UNDEF) {
+ unsigned int pba_offset = pba - (zone * zonesize);
+ result = alauda_erase_block(us, pba);
+ if (result != USB_STOR_XFER_GOOD)
+ return result;
+ MEDIA_INFO(us).pba_to_lba[zone][pba_offset] = UNDEF;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read data from a specific sector address
+ */
+static int alauda_read_data(struct us_data *us, unsigned long address,
+ unsigned int sectors)
+{
+ unsigned char *buffer;
+ u16 lba, max_lba;
+ unsigned int page, len, offset;
+ unsigned int blockshift = MEDIA_INFO(us).blockshift;
+ unsigned int pageshift = MEDIA_INFO(us).pageshift;
+ unsigned int blocksize = MEDIA_INFO(us).blocksize;
+ unsigned int pagesize = MEDIA_INFO(us).pagesize;
+ unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+ struct scatterlist *sg;
+ int result;
+
+ /*
+ * Since we only read in one block at a time, we have to create
+ * a bounce buffer and move the data a piece at a time between the
+ * bounce buffer and the actual transfer buffer.
+ * We make this buffer big enough to hold temporary redundancy data,
+ * which we use when reading the data blocks.
+ */
+
+ len = min(sectors, blocksize) * (pagesize + 64);
+ buffer = kmalloc(len, GFP_NOIO);
+ if (buffer == NULL) {
+ printk(KERN_WARNING "alauda_read_data: Out of memory\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* Figure out the initial LBA and page */
+ lba = address >> blockshift;
+ page = (address & MEDIA_INFO(us).blockmask);
+ max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);
+
+ result = USB_STOR_TRANSPORT_GOOD;
+ offset = 0;
+ sg = NULL;
+
+ while (sectors > 0) {
+ unsigned int zone = lba / uzonesize; /* integer division */
+ unsigned int lba_offset = lba - (zone * uzonesize);
+ unsigned int pages;
+ u16 pba;
+ alauda_ensure_map_for_zone(us, zone);
+
+ /* Not overflowing capacity? */
+ if (lba >= max_lba) {
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, max_lba);
+ result = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+
+ /* Find number of pages we can read in this block */
+ pages = min(sectors, blocksize - page);
+ len = pages << pageshift;
+
+ /* Find where this lba lives on disk */
+ pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
+
+ if (pba == UNDEF) { /* this lba was never written */
+ usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+ pages, lba, page);
+
+ /* This is not really an error. It just means
+ that the block has never been written.
+ Instead of returning USB_STOR_TRANSPORT_ERROR
+ it is better to return all zero data. */
+
+ memset(buffer, 0, len);
+ } else {
+ usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+ pages, pba, lba, page);
+
+ result = alauda_read_block(us, pba, page, pages, buffer);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ break;
+ }
+
+ /* Store the data in the transfer buffer */
+ usb_stor_access_xfer_buf(buffer, len, us->srb,
+ &sg, &offset, TO_XFER_BUF);
+
+ page = 0;
+ lba++;
+ sectors -= pages;
+ }
+
+ kfree(buffer);
+ return result;
+}
+
+/*
+ * Write data to a specific sector address
+ */
+static int alauda_write_data(struct us_data *us, unsigned long address,
+ unsigned int sectors)
+{
+ unsigned char *buffer, *blockbuffer;
+ unsigned int page, len, offset;
+ unsigned int blockshift = MEDIA_INFO(us).blockshift;
+ unsigned int pageshift = MEDIA_INFO(us).pageshift;
+ unsigned int blocksize = MEDIA_INFO(us).blocksize;
+ unsigned int pagesize = MEDIA_INFO(us).pagesize;
+ struct scatterlist *sg;
+ u16 lba, max_lba;
+ int result;
+
+ /*
+ * Since we don't write the user data directly to the device,
+ * we have to create a bounce buffer and move the data a piece
+ * at a time between the bounce buffer and the actual transfer buffer.
+ */
+
+ len = min(sectors, blocksize) * pagesize;
+ buffer = kmalloc(len, GFP_NOIO);
+ if (buffer == NULL) {
+ printk(KERN_WARNING "alauda_write_data: Out of memory\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /*
+ * We also need a temporary block buffer, where we read in the old data,
+ * overwrite parts with the new data, and manipulate the redundancy data
+ */
+ blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO);
+ if (blockbuffer == NULL) {
+ printk(KERN_WARNING "alauda_write_data: Out of memory\n");
+ kfree(buffer);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* Figure out the initial LBA and page */
+ lba = address >> blockshift;
+ page = (address & MEDIA_INFO(us).blockmask);
+ max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);
+
+ result = USB_STOR_TRANSPORT_GOOD;
+ offset = 0;
+ sg = NULL;
+
+ while (sectors > 0) {
+ /* Write as many sectors as possible in this block */
+ unsigned int pages = min(sectors, blocksize - page);
+ len = pages << pageshift;
+
+ /* Not overflowing capacity? */
+ if (lba >= max_lba) {
+ usb_stor_dbg(us, "Requested lba %u exceeds maximum %u\n",
+ lba, max_lba);
+ result = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+
+ /* Get the data from the transfer buffer */
+ usb_stor_access_xfer_buf(buffer, len, us->srb,
+ &sg, &offset, FROM_XFER_BUF);
+
+ result = alauda_write_lba(us, lba, page, pages, buffer,
+ blockbuffer);
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ break;
+
+ page = 0;
+ lba++;
+ sectors -= pages;
+ }
+
+ kfree(buffer);
+ kfree(blockbuffer);
+ return result;
+}
+
+/*
+ * Our interface with the rest of the world
+ */
+
+static void alauda_info_destructor(void *extra)
+{
+ struct alauda_info *info = (struct alauda_info *) extra;
+ int port;
+
+ if (!info)
+ return;
+
+ for (port = 0; port < 2; port++) {
+ struct alauda_media_info *media_info = &info->port[port];
+
+ alauda_free_maps(media_info);
+ kfree(media_info->lba_to_pba);
+ kfree(media_info->pba_to_lba);
+ }
+}
+
+/*
+ * Initialize alauda_info struct and find the data-write endpoint
+ */
+static int init_alauda(struct us_data *us)
+{
+ struct alauda_info *info;
+ struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
+ nand_init_ecc();
+
+ us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);
+ if (!us->extra)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ info = (struct alauda_info *) us->extra;
+ us->extra_destructor = alauda_info_destructor;
+
+ info->wr_ep = usb_sndbulkpipe(us->pusb_dev,
+ altsetting->endpoint[0].desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int rc;
+ struct alauda_info *info = (struct alauda_info *) us->extra;
+ unsigned char *ptr = us->iobuf;
+ static unsigned char inquiry_response[36] = {
+ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+ };
+
+ if (srb->cmnd[0] == INQUIRY) {
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
+ memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+ fill_inquiry_response(us, ptr, 36);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == TEST_UNIT_READY) {
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
+ return alauda_check_media(us);
+ }
+
+ if (srb->cmnd[0] == READ_CAPACITY) {
+ unsigned int num_zones;
+ unsigned long capacity;
+
+ rc = alauda_check_media(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift
+ + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);
+
+ capacity = num_zones * MEDIA_INFO(us).uzonesize
+ * MEDIA_INFO(us).blocksize;
+
+ /* Report capacity and page size */
+ ((__be32 *) ptr)[0] = cpu_to_be32(capacity - 1);
+ ((__be32 *) ptr)[1] = cpu_to_be32(512);
+
+ usb_stor_set_xfer_buf(ptr, 8, srb);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == READ_10) {
+ unsigned int page, pages;
+
+ rc = alauda_check_media(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+ page <<= 16;
+ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+ usb_stor_dbg(us, "READ_10: page %d pagect %d\n", page, pages);
+
+ return alauda_read_data(us, page, pages);
+ }
+
+ if (srb->cmnd[0] == WRITE_10) {
+ unsigned int page, pages;
+
+ rc = alauda_check_media(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
+
+ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+ page <<= 16;
+ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+ usb_stor_dbg(us, "WRITE_10: page %d pagect %d\n", page, pages);
+
+ return alauda_write_data(us, page, pages);
+ }
+
+ if (srb->cmnd[0] == REQUEST_SENSE) {
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
+
+ memset(ptr, 0, 18);
+ ptr[0] = 0xF0;
+ ptr[2] = info->sense_key;
+ ptr[7] = 11;
+ ptr[12] = info->sense_asc;
+ ptr[13] = info->sense_ascq;
+ usb_stor_set_xfer_buf(ptr, 18, srb);
+
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+ /* sure. whatever. not like we can stop the user from popping
+ the media out of the device (no locking doors, etc) */
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
+ info->sense_key = 0x05;
+ info->sense_asc = 0x20;
+ info->sense_ascq = 0x00;
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+static int alauda_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - alauda_usb_ids) + alauda_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "Alauda Control/Bulk";
+ us->transport = alauda_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ us->max_lun = 1;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver alauda_driver = {
+ .name = "ums-alauda",
+ .probe = alauda_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = alauda_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(alauda_driver);
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
new file mode 100644
index 00000000000..8514a2d82b7
--- /dev/null
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -0,0 +1,290 @@
+/*
+ * Support for emulating SAT (ata pass through) on devices based
+ * on the Cypress USB/ATA bridge supporting ATACB.
+ *
+ * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <linux/ata.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB");
+MODULE_AUTHOR("Matthieu Castet <castet.matthieu@free.fr>");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id cypress_usb_ids[] = {
+# include "unusual_cypress.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, cypress_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev cypress_unusual_dev_list[] = {
+# include "unusual_cypress.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * ATACB is a protocol used on cypress usb<->ata bridge to
+ * send raw ATA command over mass storage
+ * There is a ATACB2 protocol that support LBA48 on newer chip.
+ * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf
+ * datasheet from cypress.com.
+ */
+static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
+{
+ unsigned char save_cmnd[MAX_COMMAND_SIZE];
+
+ if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) {
+ usb_stor_transparent_scsi_command(srb, us);
+ return;
+ }
+
+ memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
+ memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
+
+ /* check if we support the command */
+ if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
+ goto invalid_fld;
+ /* check protocol */
+ switch((save_cmnd[1] >> 1) & 0xf) {
+ case 3: /*no DATA */
+ case 4: /* PIO in */
+ case 5: /* PIO out */
+ break;
+ default:
+ goto invalid_fld;
+ }
+
+ /* first build the ATACB command */
+ srb->cmd_len = 16;
+
+ srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command
+ this value can change, but most(all ?) manufacturers
+ keep the cypress default : 0x24 */
+ srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */
+
+ srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med
+ lba high, device, command are valid */
+ srb->cmnd[4] = 1; /* TransferBlockCount : 512 */
+
+ if (save_cmnd[0] == ATA_16) {
+ srb->cmnd[ 6] = save_cmnd[ 4]; /* features */
+ srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */
+ srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */
+ srb->cmnd[ 9] = save_cmnd[10]; /* lba med */
+ srb->cmnd[10] = save_cmnd[12]; /* lba high */
+ srb->cmnd[11] = save_cmnd[13]; /* device */
+ srb->cmnd[12] = save_cmnd[14]; /* command */
+
+ if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */
+ /* this could be supported by atacb2 */
+ if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9]
+ || save_cmnd[11])
+ goto invalid_fld;
+ }
+ }
+ else { /* ATA12 */
+ srb->cmnd[ 6] = save_cmnd[3]; /* features */
+ srb->cmnd[ 7] = save_cmnd[4]; /* sector count */
+ srb->cmnd[ 8] = save_cmnd[5]; /* lba low */
+ srb->cmnd[ 9] = save_cmnd[6]; /* lba med */
+ srb->cmnd[10] = save_cmnd[7]; /* lba high */
+ srb->cmnd[11] = save_cmnd[8]; /* device */
+ srb->cmnd[12] = save_cmnd[9]; /* command */
+
+ }
+ /* Filter SET_FEATURES - XFER MODE command */
+ if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES)
+ && (srb->cmnd[6] == SETFEATURES_XFER))
+ goto invalid_fld;
+
+ if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI)
+ srb->cmnd[2] |= (1<<7); /* set IdentifyPacketDevice for these cmds */
+
+
+ usb_stor_transparent_scsi_command(srb, us);
+
+ /* if the device doesn't support ATACB
+ */
+ if (srb->result == SAM_STAT_CHECK_CONDITION &&
+ memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
+ sizeof(usb_stor_sense_invalidCDB)) == 0) {
+ usb_stor_dbg(us, "cypress atacb not supported ???\n");
+ goto end;
+ }
+
+ /* if ck_cond flags is set, and there wasn't critical error,
+ * build the special sense
+ */
+ if ((srb->result != (DID_ERROR << 16) &&
+ srb->result != (DID_ABORT << 16)) &&
+ save_cmnd[2] & 0x20) {
+ struct scsi_eh_save ses;
+ unsigned char regs[8];
+ unsigned char *sb = srb->sense_buffer;
+ unsigned char *desc = sb + 8;
+ int tmp_result;
+
+ /* build the command for
+ * reading the ATA registers */
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs));
+
+ /* we use the same command as before, but we set
+ * the read taskfile bit, for not executing atacb command,
+ * but reading register selected in srb->cmnd[4]
+ */
+ srb->cmd_len = 16;
+ srb->cmnd = ses.cmnd;
+ srb->cmnd[2] = 1;
+
+ usb_stor_transparent_scsi_command(srb, us);
+ memcpy(regs, srb->sense_buffer, sizeof(regs));
+ tmp_result = srb->result;
+ scsi_eh_restore_cmnd(srb, &ses);
+ /* we fail to get registers, report invalid command */
+ if (tmp_result != SAM_STAT_GOOD)
+ goto invalid_fld;
+
+ /* build the sense */
+ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+ /* set sk, asc for a good command */
+ sb[1] = RECOVERED_ERROR;
+ sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */
+ sb[3] = 0x1D;
+
+ /* XXX we should generate sk, asc, ascq from status and error
+ * regs
+ * (see 11.1 Error translation ATA device error to SCSI error
+ * map, and ata_to_sense_error from libata.)
+ */
+
+ /* Sense data is current and format is descriptor. */
+ sb[0] = 0x72;
+ desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */
+
+ /* set length of additional sense data */
+ sb[7] = 14;
+ desc[1] = 12;
+
+ /* Copy registers into sense buffer. */
+ desc[ 2] = 0x00;
+ desc[ 3] = regs[1]; /* features */
+ desc[ 5] = regs[2]; /* sector count */
+ desc[ 7] = regs[3]; /* lba low */
+ desc[ 9] = regs[4]; /* lba med */
+ desc[11] = regs[5]; /* lba high */
+ desc[12] = regs[6]; /* device */
+ desc[13] = regs[7]; /* command */
+
+ srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+ }
+ goto end;
+invalid_fld:
+ srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ memcpy(srb->sense_buffer,
+ usb_stor_sense_invalidCDB,
+ sizeof(usb_stor_sense_invalidCDB));
+end:
+ memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd));
+ if (srb->cmnd[0] == ATA_12)
+ srb->cmd_len = 12;
+}
+
+
+static int cypress_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+ struct usb_device *device;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - cypress_usb_ids) + cypress_unusual_dev_list);
+ if (result)
+ return result;
+
+ /* Among CY7C68300 chips, the A revision does not support Cypress ATACB
+ * Filter out this revision from EEPROM default descriptor values
+ */
+ device = interface_to_usbdev(intf);
+ if (device->descriptor.iManufacturer != 0x38 ||
+ device->descriptor.iProduct != 0x4e ||
+ device->descriptor.iSerialNumber != 0x64) {
+ us->protocol_name = "Transparent SCSI with Cypress ATACB";
+ us->proto_handler = cypress_atacb_passthrough;
+ } else {
+ us->protocol_name = "Transparent SCSI";
+ us->proto_handler = usb_stor_transparent_scsi_command;
+ }
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver cypress_driver = {
+ .name = "ums-cypress",
+ .probe = cypress_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = cypress_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(cypress_driver);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 54e3e6c7ecd..7b17c216981 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -1,7 +1,5 @@
/* Driver for Datafab USB Compact Flash reader
*
- * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
- *
* datafab driver v0.1:
*
* First release
@@ -50,8 +48,8 @@
* in that routine.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
@@ -61,18 +59,71 @@
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "datafab.h"
+
+MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader");
+MODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>");
+MODULE_LICENSE("GPL");
+
+struct datafab_info {
+ unsigned long sectors; /* total sector count */
+ unsigned long ssize; /* sector size in bytes */
+ signed char lun; /* used for dual-slot readers */
+
+ /* the following aren't used yet */
+ unsigned char sense_key;
+ unsigned long sense_asc; /* additional sense code */
+ unsigned long sense_ascq; /* additional sense code qualifier */
+};
static int datafab_determine_lun(struct us_data *us,
struct datafab_info *info);
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id datafab_usb_ids[] = {
+# include "unusual_datafab.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, datafab_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev datafab_unusual_dev_list[] = {
+# include "unusual_datafab.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
static inline int
datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("datafab_bulk_read: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
data, len, NULL);
}
@@ -83,7 +134,7 @@ datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("datafab_bulk_write: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
data, len, NULL);
}
@@ -99,7 +150,8 @@ static int datafab_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
@@ -156,7 +208,7 @@ static int datafab_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -182,7 +234,8 @@ static int datafab_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
@@ -218,7 +271,7 @@ static int datafab_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
command[0] = 0;
command[1] = thistime;
@@ -247,9 +300,8 @@ static int datafab_write_data(struct us_data *us,
goto leave;
if (reply[0] != 0x50 && reply[1] != 0) {
- US_DEBUGP("datafab_write_data: Gah! "
- "write return code: %02x %02x\n",
- reply[0], reply[1]);
+ usb_stor_dbg(us, "Gah! write return code: %02x %02x\n",
+ reply[0], reply[1]);
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -281,7 +333,7 @@ static int datafab_determine_lun(struct us_data *us,
unsigned char *buf;
int count = 0, rc;
- if (!us || !info)
+ if (!info)
return USB_STOR_TRANSPORT_ERROR;
memcpy(command, scommand, 8);
@@ -289,7 +341,7 @@ static int datafab_determine_lun(struct us_data *us,
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("datafab_determine_lun: locating...\n");
+ usb_stor_dbg(us, "locating...\n");
// we'll try 3 times before giving up...
//
@@ -346,7 +398,7 @@ static int datafab_id_device(struct us_data *us,
unsigned char *reply;
int rc;
- if (!us || !info)
+ if (!info)
return USB_STOR_TRANSPORT_ERROR;
if (info->lun == -1) {
@@ -421,16 +473,16 @@ static int datafab_handle_mode_sense(struct us_data *us,
switch (pc) {
case 0x0:
- US_DEBUGP("datafab_handle_mode_sense: Current values\n");
+ usb_stor_dbg(us, "Current values\n");
break;
case 0x1:
- US_DEBUGP("datafab_handle_mode_sense: Changeable values\n");
+ usb_stor_dbg(us, "Changeable values\n");
break;
case 0x2:
- US_DEBUGP("datafab_handle_mode_sense: Default values\n");
+ usb_stor_dbg(us, "Default values\n");
break;
case 0x3:
- US_DEBUGP("datafab_handle_mode_sense: Saves values\n");
+ usb_stor_dbg(us, "Saves values\n");
break;
}
@@ -501,7 +553,7 @@ static void datafab_info_destructor(void *extra)
// Transport for the Datafab MDCFE-B
//
-int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
+static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct datafab_info *info;
int rc;
@@ -512,13 +564,10 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
};
if (!us->extra) {
- us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("datafab_transport: Gah! "
- "Can't allocate storage for Datafab info struct!\n");
+ us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
+ if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- }
- memset(us->extra, 0, sizeof(struct datafab_info));
+
us->extra_destructor = datafab_info_destructor;
((struct datafab_info *)us->extra)->lun = -1;
}
@@ -526,7 +575,7 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
info = (struct datafab_info *) (us->extra);
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_reply, sizeof(inquiry_reply));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -538,8 +587,8 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
// build the reply
// we need the last sector, not the number of sectors
@@ -551,7 +600,7 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("datafab_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -563,7 +612,8 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("datafab_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_read_data(us, info, block, blocks);
}
@@ -576,7 +626,8 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("datafab_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_read_data(us, info, block, blocks);
}
@@ -586,7 +637,8 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("datafab_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_write_data(us, info, block, blocks);
}
@@ -599,17 +651,18 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
return datafab_id_device(us, info);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("datafab_transport: REQUEST_SENSE. Returning faked response\n");
+ usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n");
// this response is pretty bogus right now. eventually if necessary
// we can set the correct sense data. so far though it hasn't been
@@ -627,12 +680,12 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SENSE) {
- US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
return datafab_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
- US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
return datafab_handle_mode_sense(us, srb, 0);
}
@@ -646,7 +699,7 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
if (srb->cmnd[0] == START_STOP) {
/* this is used by sd.c'check_scsidisk_media_change to detect
media change */
- US_DEBUGP("datafab_transport: START_STOP.\n");
+ usb_stor_dbg(us, "START_STOP\n");
/* the first datafab_id_device after a media change returns
an error (determined experimentally) */
rc = datafab_id_device(us, info);
@@ -660,10 +713,46 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
return rc;
}
- US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
return USB_STOR_TRANSPORT_FAILED;
}
+
+static int datafab_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - datafab_usb_ids) + datafab_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "Datafab Bulk-Only";
+ us->transport = datafab_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ us->max_lun = 1;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver datafab_driver = {
+ .name = "ums-datafab",
+ .probe = datafab_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = datafab_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(datafab_driver);
diff --git a/drivers/usb/storage/datafab.h b/drivers/usb/storage/datafab.h
deleted file mode 100644
index 32e3f271e58..00000000000
--- a/drivers/usb/storage/datafab.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Driver for Datafab MDCFE-B USB Compact Flash reader
- * Header File
- *
- * Current development and maintenance by:
- * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
- *
- * See datafab.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _USB_DATAFAB_MDCFE_B_H
-#define _USB_DATAFAB_MDCFE_B_H
-
-extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us);
-
-struct datafab_info {
- unsigned long sectors; // total sector count
- unsigned long ssize; // sector size in bytes
- signed char lun; // used for dual-slot readers
-
- // the following aren't used yet
- unsigned char sense_key;
- unsigned long sense_asc; // additional sense code
- unsigned long sense_ascq; // additional sense code qualifier
-};
-
-#endif
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index 5a9321705a7..e08f64780e3 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Source Code File
*
- * $Id: debug.c,v 1.9 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -44,16 +42,19 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/device.h>
#include <linux/cdrom.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
+#include "usb.h"
#include "debug.h"
#include "scsi.h"
-void usb_stor_show_command(struct scsi_cmnd *srb)
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
{
char *what = NULL;
int i;
@@ -132,6 +133,7 @@ void usb_stor_show_command(struct scsi_cmnd *srb)
case 0x5C: what = "READ BUFFER CAPACITY"; break;
case 0x5D: what = "SEND CUE SHEET"; break;
case GPCMD_BLANK: what = "BLANK"; break;
+ case REPORT_LUNS: what = "REPORT LUNS"; break;
case MOVE_MEDIUM: what = "MOVE_MEDIUM or PLAY AUDIO (12)"; break;
case READ_12: what = "READ_12"; break;
case WRITE_12: what = "WRITE_12"; break;
@@ -150,18 +152,18 @@ void usb_stor_show_command(struct scsi_cmnd *srb)
case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
default: what = "(unknown command)"; break;
}
- US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
- US_DEBUGP("");
+ usb_stor_dbg(us, "Command %s (%d bytes)\n", what, srb->cmd_len);
+ usb_stor_dbg(us, "bytes: ");
for (i = 0; i < srb->cmd_len && i < 16; i++)
US_DEBUGPX(" %02x", srb->cmnd[i]);
US_DEBUGPX("\n");
}
-void usb_stor_show_sense(
- unsigned char key,
- unsigned char asc,
- unsigned char ascq) {
-
+void usb_stor_show_sense(const struct us_data *us,
+ unsigned char key,
+ unsigned char asc,
+ unsigned char ascq)
+{
const char *what, *keystr;
keystr = scsi_sense_key_string(key);
@@ -172,7 +174,22 @@ void usb_stor_show_sense(
if (what == NULL)
what = "(unknown ASC/ASCQ)";
- US_DEBUGP("%s: ", keystr);
+ usb_stor_dbg(us, "%s: ", keystr);
US_DEBUGPX(what, ascq);
US_DEBUGPX("\n");
}
+
+int usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(usb_stor_dbg);
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index cd2096acc72..b1273f03e22 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Header File
*
- * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -44,21 +42,27 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
-#include <linux/config.h>
#include <linux/kernel.h>
#define USB_STORAGE "usb-storage: "
#ifdef CONFIG_USB_STORAGE_DEBUG
-void usb_stor_show_command(struct scsi_cmnd *srb);
-void usb_stor_show_sense( unsigned char key,
- unsigned char asc, unsigned char ascq );
-#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
-#define US_DEBUGPX(x...) printk( x )
-#define US_DEBUG(x) x
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb);
+void usb_stor_show_sense(const struct us_data *us, unsigned char key,
+ unsigned char asc, unsigned char ascq);
+__printf(2, 3) int usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...);
+
+#define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__)
+#define US_DEBUG(x) x
#else
-#define US_DEBUGP(x...)
-#define US_DEBUGPX(x...)
+__printf(2, 3)
+static inline int _usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...) {return 1;}
+#define usb_stor_dbg(us, fmt, ...) \
+ do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0)
+#define US_DEBUGPX(fmt, ...) \
+ do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
#define US_DEBUG(x)
#endif
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
deleted file mode 100644
index 92b69e4c804..00000000000
--- a/drivers/usb/storage/dpcm.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
- *
- * $Id: dpcm.c,v 1.4 2001/06/11 02:54:25 mdharm Exp $
- *
- * DPCM driver v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 Brian Webb (webbb@earthlink.net)
- *
- * This device contains both a CompactFlash card reader, which
- * uses the Control/Bulk w/o Interrupt protocol and
- * a SmartMedia card reader that uses the same protocol
- * as the SDDR09.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-
-#include "usb.h"
-#include "transport.h"
-#include "protocol.h"
-#include "debug.h"
-#include "dpcm.h"
-#include "sddr09.h"
-
-/*
- * Transport for the Microtech DPCM-USB
- *
- */
-int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
-{
- int ret;
-
- if(srb == NULL)
- return USB_STOR_TRANSPORT_ERROR;
-
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
-
- switch(srb->device->lun) {
- case 0:
-
- /*
- * LUN 0 corresponds to the CompactFlash card reader.
- */
- ret = usb_stor_CB_transport(srb, us);
- break;
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- case 1:
-
- /*
- * LUN 1 corresponds to the SmartMedia card reader.
- */
-
- /*
- * Set the LUN to 0 (just in case).
- */
- srb->device->lun = 0; us->srb->device->lun = 0;
- ret = sddr09_transport(srb, us);
- srb->device->lun = 1; us->srb->device->lun = 1;
- break;
-
-#endif
-
- default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
- ret = USB_STOR_TRANSPORT_ERROR;
- break;
- }
- return ret;
-}
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
new file mode 100644
index 00000000000..ef6efb55dc3
--- /dev/null
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -0,0 +1,2420 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <linux/firmware.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+
+#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
+#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
+#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
+#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
+#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
+#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
+
+MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
+MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
+MODULE_FIRMWARE(SD_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_INIT_FIRMWARE);
+MODULE_FIRMWARE(MSP_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_RW_FIRMWARE);
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags)}
+
+static struct usb_device_id ene_ub6250_usb_ids[] = {
+# include "unusual_ene_ub6250.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
+# include "unusual_ene_ub6250.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+
+/* ENE bin code len */
+#define ENE_BIN_CODE_LEN 0x800
+/* EnE HW Register */
+#define REG_CARD_STATUS 0xFF83
+#define REG_HW_TRAP1 0xFF89
+
+/* SRB Status */
+#define SS_SUCCESS 0x00 /* No Sense */
+#define SS_NOT_READY 0x02
+#define SS_MEDIUM_ERR 0x03
+#define SS_HW_ERR 0x04
+#define SS_ILLEGAL_REQUEST 0x05
+#define SS_UNIT_ATTENTION 0x06
+
+/* ENE Load FW Pattern */
+#define SD_INIT1_PATTERN 1
+#define SD_INIT2_PATTERN 2
+#define SD_RW_PATTERN 3
+#define MS_INIT_PATTERN 4
+#define MSP_RW_PATTERN 5
+#define MS_RW_PATTERN 6
+#define SM_INIT_PATTERN 7
+#define SM_RW_PATTERN 8
+
+#define FDIR_WRITE 0
+#define FDIR_READ 1
+
+/* For MS Card */
+
+/* Status Register 1 */
+#define MS_REG_ST1_MB 0x80 /* media busy */
+#define MS_REG_ST1_FB1 0x40 /* flush busy 1 */
+#define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */
+#define MS_REG_ST1_UCDT 0x10 /* unable to correct data */
+#define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */
+#define MS_REG_ST1_UCEX 0x04 /* unable to correct extra */
+#define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */
+#define MS_REG_ST1_UCFG 0x01 /* unable to correct overwrite flag */
+#define MS_REG_ST1_DEFAULT (MS_REG_ST1_MB | MS_REG_ST1_FB1 | MS_REG_ST1_DTER | MS_REG_ST1_UCDT | MS_REG_ST1_EXER | MS_REG_ST1_UCEX | MS_REG_ST1_FGER | MS_REG_ST1_UCFG)
+
+/* Overwrite Area */
+#define MS_REG_OVR_BKST 0x80 /* block status */
+#define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */
+#define MS_REG_OVR_BKST_NG 0x00 /* NG */
+#define MS_REG_OVR_PGST0 0x40 /* page status */
+#define MS_REG_OVR_PGST1 0x20
+#define MS_REG_OVR_PGST_MASK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1)
+#define MS_REG_OVR_PGST_OK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */
+#define MS_REG_OVR_PGST_NG MS_REG_OVR_PGST1 /* NG */
+#define MS_REG_OVR_PGST_DATA_ERROR 0x00 /* data error */
+#define MS_REG_OVR_UDST 0x10 /* update status */
+#define MS_REG_OVR_UDST_UPDATING 0x00 /* updating */
+#define MS_REG_OVR_UDST_NO_UPDATE MS_REG_OVR_UDST
+#define MS_REG_OVR_RESERVED 0x08
+#define MS_REG_OVR_DEFAULT (MS_REG_OVR_BKST_OK | MS_REG_OVR_PGST_OK | MS_REG_OVR_UDST_NO_UPDATE | MS_REG_OVR_RESERVED)
+
+/* Management Flag */
+#define MS_REG_MNG_SCMS0 0x20 /* serial copy management system */
+#define MS_REG_MNG_SCMS1 0x10
+#define MS_REG_MNG_SCMS_MASK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
+#define MS_REG_MNG_SCMS_COPY_OK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
+#define MS_REG_MNG_SCMS_ONE_COPY MS_REG_MNG_SCMS1
+#define MS_REG_MNG_SCMS_NO_COPY 0x00
+#define MS_REG_MNG_ATFLG 0x08 /* address transfer table flag */
+#define MS_REG_MNG_ATFLG_OTHER MS_REG_MNG_ATFLG /* other */
+#define MS_REG_MNG_ATFLG_ATTBL 0x00 /* address transfer table */
+#define MS_REG_MNG_SYSFLG 0x04 /* system flag */
+#define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */
+#define MS_REG_MNG_SYSFLG_BOOT 0x00 /* system block */
+#define MS_REG_MNG_RESERVED 0xc3
+#define MS_REG_MNG_DEFAULT (MS_REG_MNG_SCMS_COPY_OK | MS_REG_MNG_ATFLG_OTHER | MS_REG_MNG_SYSFLG_USER | MS_REG_MNG_RESERVED)
+
+
+#define MS_MAX_PAGES_PER_BLOCK 32
+#define MS_MAX_INITIAL_ERROR_BLOCKS 10
+#define MS_LIB_BITS_PER_BYTE 8
+
+#define MS_SYSINF_FORMAT_FAT 1
+#define MS_SYSINF_USAGE_GENERAL 0
+
+#define MS_SYSINF_MSCLASS_TYPE_1 1
+#define MS_SYSINF_PAGE_SIZE MS_BYTES_PER_PAGE /* fixed */
+
+#define MS_SYSINF_CARDTYPE_RDONLY 1
+#define MS_SYSINF_CARDTYPE_RDWR 2
+#define MS_SYSINF_CARDTYPE_HYBRID 3
+#define MS_SYSINF_SECURITY 0x01
+#define MS_SYSINF_SECURITY_NO_SUPPORT MS_SYSINF_SECURITY
+#define MS_SYSINF_SECURITY_SUPPORT 0
+
+#define MS_SYSINF_RESERVED1 1
+#define MS_SYSINF_RESERVED2 1
+
+#define MS_SYSENT_TYPE_INVALID_BLOCK 0x01
+#define MS_SYSENT_TYPE_CIS_IDI 0x0a /* CIS/IDI */
+
+#define SIZE_OF_KIRO 1024
+#define BYTE_MASK 0xff
+
+/* ms error code */
+#define MS_STATUS_WRITE_PROTECT 0x0106
+#define MS_STATUS_SUCCESS 0x0000
+#define MS_ERROR_FLASH_READ 0x8003
+#define MS_ERROR_FLASH_ERASE 0x8005
+#define MS_LB_ERROR 0xfff0
+#define MS_LB_BOOT_BLOCK 0xfff1
+#define MS_LB_INITIAL_ERROR 0xfff2
+#define MS_STATUS_SUCCESS_WITH_ECC 0xfff3
+#define MS_LB_ACQUIRED_ERROR 0xfff4
+#define MS_LB_NOT_USED_ERASED 0xfff5
+#define MS_NOCARD_ERROR 0xfff8
+#define MS_NO_MEMORY_ERROR 0xfff9
+#define MS_STATUS_INT_ERROR 0xfffa
+#define MS_STATUS_ERROR 0xfffe
+#define MS_LB_NOT_USED 0xffff
+
+#define MS_REG_MNG_SYSFLG 0x04 /* system flag */
+#define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */
+
+#define MS_BOOT_BLOCK_ID 0x0001
+#define MS_BOOT_BLOCK_FORMAT_VERSION 0x0100
+#define MS_BOOT_BLOCK_DATA_ENTRIES 2
+
+#define MS_NUMBER_OF_SYSTEM_ENTRY 4
+#define MS_NUMBER_OF_BOOT_BLOCK 2
+#define MS_BYTES_PER_PAGE 512
+#define MS_LOGICAL_BLOCKS_PER_SEGMENT 496
+#define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT 494
+
+#define MS_PHYSICAL_BLOCKS_PER_SEGMENT 0x200 /* 512 */
+#define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK 0x1ff
+
+/* overwrite area */
+#define MS_REG_OVR_BKST 0x80 /* block status */
+#define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */
+#define MS_REG_OVR_BKST_NG 0x00 /* NG */
+
+/* Status Register 1 */
+#define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */
+#define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */
+#define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */
+
+/* MemoryStick Register */
+/* Status Register 0 */
+#define MS_REG_ST0_WP 0x01 /* write protected */
+#define MS_REG_ST0_WP_ON MS_REG_ST0_WP
+
+#define MS_LIB_CTRL_RDONLY 0
+#define MS_LIB_CTRL_WRPROTECT 1
+
+/*dphy->log table */
+#define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock])
+#define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock])
+
+#define ms_lib_ctrl_set(pdx, Flag) ((pdx)->MS_Lib.flags |= (1 << (Flag)))
+#define ms_lib_ctrl_reset(pdx, Flag) ((pdx)->MS_Lib.flags &= ~(1 << (Flag)))
+#define ms_lib_ctrl_check(pdx, Flag) ((pdx)->MS_Lib.flags & (1 << (Flag)))
+
+#define ms_lib_iswritable(pdx) ((ms_lib_ctrl_check((pdx), MS_LIB_CTRL_RDONLY) == 0) && (ms_lib_ctrl_check(pdx, MS_LIB_CTRL_WRPROTECT) == 0))
+#define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap))
+#define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0))
+
+
+struct SD_STATUS {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMMC:1;
+ u8 HiCapacity:1;
+ u8 HiSpeed:1;
+ u8 WtP:1;
+ u8 Reserved:1;
+};
+
+struct MS_STATUS {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMSPro:1;
+ u8 IsMSPHG:1;
+ u8 Reserved1:1;
+ u8 WtP:1;
+ u8 Reserved2:1;
+};
+
+struct SM_STATUS {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 Reserved:3;
+ u8 WtP:1;
+ u8 IsMS:1;
+};
+
+struct ms_bootblock_cis {
+ u8 bCistplDEVICE[6]; /* 0 */
+ u8 bCistplDEVICE0C[6]; /* 6 */
+ u8 bCistplJEDECC[4]; /* 12 */
+ u8 bCistplMANFID[6]; /* 16 */
+ u8 bCistplVER1[32]; /* 22 */
+ u8 bCistplFUNCID[4]; /* 54 */
+ u8 bCistplFUNCE0[4]; /* 58 */
+ u8 bCistplFUNCE1[5]; /* 62 */
+ u8 bCistplCONF[7]; /* 67 */
+ u8 bCistplCFTBLENT0[10];/* 74 */
+ u8 bCistplCFTBLENT1[8]; /* 84 */
+ u8 bCistplCFTBLENT2[12];/* 92 */
+ u8 bCistplCFTBLENT3[8]; /* 104 */
+ u8 bCistplCFTBLENT4[17];/* 112 */
+ u8 bCistplCFTBLENT5[8]; /* 129 */
+ u8 bCistplCFTBLENT6[17];/* 137 */
+ u8 bCistplCFTBLENT7[8]; /* 154 */
+ u8 bCistplNOLINK[3]; /* 162 */
+} ;
+
+struct ms_bootblock_idi {
+#define MS_IDI_GENERAL_CONF 0x848A
+ u16 wIDIgeneralConfiguration; /* 0 */
+ u16 wIDInumberOfCylinder; /* 1 */
+ u16 wIDIreserved0; /* 2 */
+ u16 wIDInumberOfHead; /* 3 */
+ u16 wIDIbytesPerTrack; /* 4 */
+ u16 wIDIbytesPerSector; /* 5 */
+ u16 wIDIsectorsPerTrack; /* 6 */
+ u16 wIDItotalSectors[2]; /* 7-8 high,low */
+ u16 wIDIreserved1[11]; /* 9-19 */
+ u16 wIDIbufferType; /* 20 */
+ u16 wIDIbufferSize; /* 21 */
+ u16 wIDIlongCmdECC; /* 22 */
+ u16 wIDIfirmVersion[4]; /* 23-26 */
+ u16 wIDImodelName[20]; /* 27-46 */
+ u16 wIDIreserved2; /* 47 */
+ u16 wIDIlongWordSupported; /* 48 */
+ u16 wIDIdmaSupported; /* 49 */
+ u16 wIDIreserved3; /* 50 */
+ u16 wIDIpioTiming; /* 51 */
+ u16 wIDIdmaTiming; /* 52 */
+ u16 wIDItransferParameter; /* 53 */
+ u16 wIDIformattedCylinder; /* 54 */
+ u16 wIDIformattedHead; /* 55 */
+ u16 wIDIformattedSectorsPerTrack;/* 56 */
+ u16 wIDIformattedTotalSectors[2];/* 57-58 */
+ u16 wIDImultiSector; /* 59 */
+ u16 wIDIlbaSectors[2]; /* 60-61 */
+ u16 wIDIsingleWordDMA; /* 62 */
+ u16 wIDImultiWordDMA; /* 63 */
+ u16 wIDIreserved4[192]; /* 64-255 */
+};
+
+struct ms_bootblock_sysent_rec {
+ u32 dwStart;
+ u32 dwSize;
+ u8 bType;
+ u8 bReserved[3];
+};
+
+struct ms_bootblock_sysent {
+ struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY];
+};
+
+struct ms_bootblock_sysinf {
+ u8 bMsClass; /* must be 1 */
+ u8 bCardType; /* see below */
+ u16 wBlockSize; /* n KB */
+ u16 wBlockNumber; /* number of physical block */
+ u16 wTotalBlockNumber; /* number of logical block */
+ u16 wPageSize; /* must be 0x200 */
+ u8 bExtraSize; /* 0x10 */
+ u8 bSecuritySupport;
+ u8 bAssemblyDate[8];
+ u8 bFactoryArea[4];
+ u8 bAssemblyMakerCode;
+ u8 bAssemblyMachineCode[3];
+ u16 wMemoryMakerCode;
+ u16 wMemoryDeviceCode;
+ u16 wMemorySize;
+ u8 bReserved1;
+ u8 bReserved2;
+ u8 bVCC;
+ u8 bVPP;
+ u16 wControllerChipNumber;
+ u16 wControllerFunction; /* New MS */
+ u8 bReserved3[9]; /* New MS */
+ u8 bParallelSupport; /* New MS */
+ u16 wFormatValue; /* New MS */
+ u8 bFormatType;
+ u8 bUsage;
+ u8 bDeviceType;
+ u8 bReserved4[22];
+ u8 bFUValue3;
+ u8 bFUValue4;
+ u8 bReserved5[15];
+};
+
+struct ms_bootblock_header {
+ u16 wBlockID;
+ u16 wFormatVersion;
+ u8 bReserved1[184];
+ u8 bNumberOfDataEntry;
+ u8 bReserved2[179];
+};
+
+struct ms_bootblock_page0 {
+ struct ms_bootblock_header header;
+ struct ms_bootblock_sysent sysent;
+ struct ms_bootblock_sysinf sysinf;
+};
+
+struct ms_bootblock_cis_idi {
+ union {
+ struct ms_bootblock_cis cis;
+ u8 dmy[256];
+ } cis;
+
+ union {
+ struct ms_bootblock_idi idi;
+ u8 dmy[256];
+ } idi;
+
+};
+
+/* ENE MS Lib struct */
+struct ms_lib_type_extdat {
+ u8 reserved;
+ u8 intr;
+ u8 status0;
+ u8 status1;
+ u8 ovrflg;
+ u8 mngflg;
+ u16 logadr;
+};
+
+struct ms_lib_ctrl {
+ u32 flags;
+ u32 BytesPerSector;
+ u32 NumberOfCylinder;
+ u32 SectorsPerCylinder;
+ u16 cardType; /* R/W, RO, Hybrid */
+ u16 blockSize;
+ u16 PagesPerBlock;
+ u16 NumberOfPhyBlock;
+ u16 NumberOfLogBlock;
+ u16 NumberOfSegment;
+ u16 *Phy2LogMap; /* phy2log table */
+ u16 *Log2PhyMap; /* log2phy table */
+ u16 wrtblk;
+ unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE];
+ unsigned char *blkpag;
+ struct ms_lib_type_extdat *blkext;
+ unsigned char copybuf[512];
+};
+
+
+/* SD Block Length */
+/* 2^9 = 512 Bytes, The HW maximum read/write data length */
+#define SD_BLOCK_LEN 9
+
+struct ene_ub6250_info {
+ /* for 6250 code */
+ struct SD_STATUS SD_Status;
+ struct MS_STATUS MS_Status;
+ struct SM_STATUS SM_Status;
+
+ /* ----- SD Control Data ---------------- */
+ /*SD_REGISTER SD_Regs; */
+ u16 SD_Block_Mult;
+ u8 SD_READ_BL_LEN;
+ u16 SD_C_SIZE;
+ u8 SD_C_SIZE_MULT;
+
+ /* SD/MMC New spec. */
+ u8 SD_SPEC_VER;
+ u8 SD_CSD_VER;
+ u8 SD20_HIGH_CAPACITY;
+ u32 HC_C_SIZE;
+ u8 MMC_SPEC_VER;
+ u8 MMC_BusWidth;
+ u8 MMC_HIGH_CAPACITY;
+
+ /*----- MS Control Data ---------------- */
+ bool MS_SWWP;
+ u32 MSP_TotalBlock;
+ struct ms_lib_ctrl MS_Lib;
+ bool MS_IsRWPage;
+ u16 MS_Model;
+
+ /*----- SM Control Data ---------------- */
+ u8 SM_DeviceID;
+ u8 SM_CardID;
+
+ unsigned char *testbuf;
+ u8 BIN_FLAG;
+ u32 bl_num;
+ int SrbStatus;
+
+ /*------Power Managerment ---------------*/
+ bool Power_IsResum;
+};
+
+static int ene_sd_init(struct us_data *us);
+static int ene_ms_init(struct us_data *us);
+static int ene_load_bincode(struct us_data *us, unsigned char flag);
+
+static void ene_ub6250_info_destructor(void *extra)
+{
+ if (!extra)
+ return;
+}
+
+static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+
+ int result;
+ unsigned int residue;
+ unsigned int cswlen = 0, partial = 0;
+ unsigned int transfer_length = bcb->DataTransferLength;
+
+ /* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, US_BULK_CB_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (buf) {
+ unsigned int pipe = fDir;
+
+ if (fDir == FDIR_READ)
+ pipe = us->recv_bulk_pipe;
+ else
+ pipe = us->send_bulk_pipe;
+
+ /* Bulk */
+ if (use_sg) {
+ result = usb_stor_bulk_srb(us, pipe, us->srb);
+ } else {
+ result = usb_stor_bulk_transfer_sg(us, pipe, buf,
+ transfer_length, 0, &partial);
+ }
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "data transfer fail ---\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen);
+
+ if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+ usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ }
+
+ if (result == USB_STOR_XFER_STALLED) {
+ /* get the status again */
+ usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, NULL);
+ }
+
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* check bulk status */
+ residue = le32_to_cpu(bcs->Residue);
+
+ /* try to compute the actual residue, based on how much data
+ * was really transferred and what the device tells us */
+ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+ residue = min(residue, transfer_length);
+ if (us->srb != NULL)
+ scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
+ (int)residue));
+ }
+
+ if (bcs->Status != US_BULK_STAT_OK)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (info->SD_Status.Insert && info->SD_Status.Ready)
+ return USB_STOR_TRANSPORT_GOOD;
+ else {
+ ene_sd_init(us);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
+{
+ unsigned char data_ptr[36] = {
+ 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
+ 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
+ 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
+
+ usb_stor_set_xfer_buf(data_ptr, 36, srb);
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ unsigned char mediaNoWP[12] = {
+ 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+ unsigned char mediaWP[12] = {
+ 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+
+ if (info->SD_Status.WtP)
+ usb_stor_set_xfer_buf(mediaWP, 12, srb);
+ else
+ usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
+
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
+{
+ u32 bl_num;
+ u32 bl_len;
+ unsigned int offset = 0;
+ unsigned char buf[8];
+ struct scatterlist *sg = NULL;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ usb_stor_dbg(us, "sd_scsi_read_capacity\n");
+ if (info->SD_Status.HiCapacity) {
+ bl_len = 0x200;
+ if (info->SD_Status.IsMMC)
+ bl_num = info->HC_C_SIZE-1;
+ else
+ bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
+ } else {
+ bl_len = 1 << (info->SD_READ_BL_LEN);
+ bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
+ * (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
+ }
+ info->bl_num = bl_num;
+ usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+ usb_stor_dbg(us, "bl_num = %x\n", bl_num);
+
+ /*srb->request_bufflen = 8; */
+ buf[0] = (bl_num >> 24) & 0xff;
+ buf[1] = (bl_num >> 16) & 0xff;
+ buf[2] = (bl_num >> 8) & 0xff;
+ buf[3] = (bl_num >> 0) & 0xff;
+ buf[4] = (bl_len >> 24) & 0xff;
+ buf[5] = (bl_len >> 16) & 0xff;
+ buf[6] = (bl_len >> 8) & 0xff;
+ buf[7] = (bl_len >> 0) & 0xff;
+
+ usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ unsigned char *cdb = srb->cmnd;
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+ ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+ u32 bnByte = bn * 0x200;
+ u32 blenByte = blen * 0x200;
+
+ if (bn > info->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ result = ene_load_bincode(us, SD_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (info->SD_Status.HiCapacity)
+ bnByte = bn;
+
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = blenByte;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[5] = (unsigned char)(bnByte);
+ bcb->CDB[4] = (unsigned char)(bnByte>>8);
+ bcb->CDB[3] = (unsigned char)(bnByte>>16);
+ bcb->CDB[2] = (unsigned char)(bnByte>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
+ return result;
+}
+
+static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ unsigned char *cdb = srb->cmnd;
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+ ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+ u32 bnByte = bn * 0x200;
+ u32 blenByte = blen * 0x200;
+
+ if (bn > info->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ result = ene_load_bincode(us, SD_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (info->SD_Status.HiCapacity)
+ bnByte = bn;
+
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = blenByte;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xF0;
+ bcb->CDB[5] = (unsigned char)(bnByte);
+ bcb->CDB[4] = (unsigned char)(bnByte>>8);
+ bcb->CDB[3] = (unsigned char)(bnByte>>16);
+ bcb->CDB[2] = (unsigned char)(bnByte>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
+ return result;
+}
+
+/*
+ * ENE MS Card
+ */
+
+static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock))
+ return (u32)-1;
+
+ info->MS_Lib.Phy2LogMap[phyblk] = logblk;
+ info->MS_Lib.Log2PhyMap[logblk] = phyblk;
+
+ return 0;
+}
+
+static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+ return (u32)-1;
+
+ info->MS_Lib.Phy2LogMap[phyblk] = mark;
+
+ return 0;
+}
+
+static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk)
+{
+ return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR);
+}
+
+static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk)
+{
+ return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK);
+}
+
+static int ms_lib_free_logicalmap(struct us_data *us)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ kfree(info->MS_Lib.Phy2LogMap);
+ info->MS_Lib.Phy2LogMap = NULL;
+
+ kfree(info->MS_Lib.Log2PhyMap);
+ info->MS_Lib.Log2PhyMap = NULL;
+
+ return 0;
+}
+
+static int ms_lib_alloc_logicalmap(struct us_data *us)
+{
+ u32 i;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ info->MS_Lib.Phy2LogMap = kmalloc(info->MS_Lib.NumberOfPhyBlock * sizeof(u16), GFP_KERNEL);
+ info->MS_Lib.Log2PhyMap = kmalloc(info->MS_Lib.NumberOfLogBlock * sizeof(u16), GFP_KERNEL);
+
+ if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) {
+ ms_lib_free_logicalmap(us);
+ return (u32)-1;
+ }
+
+ for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++)
+ info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED;
+
+ for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++)
+ info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED;
+
+ return 0;
+}
+
+static void ms_lib_clear_writebuf(struct us_data *us)
+{
+ int i;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ info->MS_Lib.wrtblk = (u16)-1;
+ ms_lib_clear_pagemap(info);
+
+ if (info->MS_Lib.blkpag)
+ memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector);
+
+ if (info->MS_Lib.blkext) {
+ for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) {
+ info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT;
+ info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT;
+ info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT;
+ info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED;
+ }
+ }
+}
+
+static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
+{
+ u32 Ende, Count;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+ for (Count = 0; PhyBlock < Ende; PhyBlock++) {
+ switch (info->MS_Lib.Phy2LogMap[PhyBlock]) {
+ case MS_LB_NOT_USED:
+ case MS_LB_NOT_USED_ERASED:
+ Count++;
+ default:
+ break;
+ }
+ }
+
+ return Count;
+}
+
+static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
+ u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u8 ExtBuf[4];
+ u32 bn = PhyBlockAddr * 0x20 + PageNum;
+
+ /* printk(KERN_INFO "MS --- MS_ReaderReadPage,
+ PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */
+
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* Read Page Data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+
+ bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */
+
+ bcb->CDB[5] = (unsigned char)(bn);
+ bcb->CDB[4] = (unsigned char)(bn>>8);
+ bcb->CDB[3] = (unsigned char)(bn>>16);
+ bcb->CDB[2] = (unsigned char)(bn>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+
+ /* Read Extra Data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x4;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+
+ bcb->CDB[5] = (unsigned char)(PageNum);
+ bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
+ bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
+ bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
+ bcb->CDB[6] = 0x01;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ ExtraDat->reserved = 0;
+ ExtraDat->intr = 0x80; /* Not yet,fireware support */
+ ExtraDat->status0 = 0x10; /* Not yet,fireware support */
+
+ ExtraDat->status1 = 0x00; /* Not yet,fireware support */
+ ExtraDat->ovrflg = ExtBuf[0];
+ ExtraDat->mngflg = ExtBuf[1];
+ ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData)
+{
+ struct ms_bootblock_sysent *SysEntry;
+ struct ms_bootblock_sysinf *SysInfo;
+ u32 i, result;
+ u8 PageNumber;
+ u8 *PageBuffer;
+ struct ms_lib_type_extdat ExtraData;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+ if (PageBuffer == NULL)
+ return (u32)-1;
+
+ result = (u32)-1;
+
+ SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf);
+
+ if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) ||
+ (be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) ||
+ ((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) ||
+ (SysInfo->bReserved1 != MS_SYSINF_RESERVED1) ||
+ (SysInfo->bReserved2 != MS_SYSINF_RESERVED2) ||
+ (SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) ||
+ (SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL))
+ goto exit;
+ /* */
+ switch (info->MS_Lib.cardType = SysInfo->bCardType) {
+ case MS_SYSINF_CARDTYPE_RDONLY:
+ ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY);
+ break;
+ case MS_SYSINF_CARDTYPE_RDWR:
+ ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY);
+ break;
+ case MS_SYSINF_CARDTYPE_HYBRID:
+ default:
+ goto exit;
+ }
+
+ info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize);
+ info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber);
+ info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2;
+ info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE;
+ info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+ info->MS_Model = be16_to_cpu(SysInfo->wMemorySize);
+
+ /*Allocate to all number of logicalblock and physicalblock */
+ if (ms_lib_alloc_logicalmap(us))
+ goto exit;
+
+ /* Mark the book block */
+ ms_lib_set_bootblockmark(us, PhyBlock);
+
+ SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent);
+
+ for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) {
+ u32 EntryOffset, EntrySize;
+
+ EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart);
+
+ if (EntryOffset == 0xffffff)
+ continue;
+ EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize);
+
+ if (EntrySize == 0)
+ continue;
+
+ if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO)
+ continue;
+
+ if (i == 0) {
+ u8 PrevPageNumber = 0;
+ u16 phyblk;
+
+ if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK)
+ goto exit;
+
+ while (EntrySize > 0) {
+
+ PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1);
+ if (PageNumber != PrevPageNumber) {
+ switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) {
+ case MS_STATUS_SUCCESS:
+ break;
+ case MS_STATUS_WRITE_PROTECT:
+ case MS_ERROR_FLASH_READ:
+ case MS_STATUS_ERROR:
+ default:
+ goto exit;
+ }
+
+ PrevPageNumber = PageNumber;
+ }
+
+ phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)));
+ if (phyblk < 0x0fff)
+ ms_lib_set_initialerrorblock(us, phyblk);
+
+ EntryOffset += 2;
+ EntrySize -= 2;
+ }
+ } else if (i == 1) { /* CIS/IDI */
+ struct ms_bootblock_idi *idi;
+
+ if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI)
+ goto exit;
+
+ switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) {
+ case MS_STATUS_SUCCESS:
+ break;
+ case MS_STATUS_WRITE_PROTECT:
+ case MS_ERROR_FLASH_READ:
+ case MS_STATUS_ERROR:
+ default:
+ goto exit;
+ }
+
+ idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi;
+ if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF)
+ goto exit;
+
+ info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector);
+ if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE)
+ goto exit;
+ }
+ } /* End for .. */
+
+ result = 0;
+
+exit:
+ if (result)
+ ms_lib_free_logicalmap(us);
+
+ kfree(PageBuffer);
+
+ result = 0;
+ return result;
+}
+
+static void ms_lib_free_writebuf(struct us_data *us)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */
+
+ /* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */
+
+ ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */
+
+ if (info->MS_Lib.blkpag) {
+ kfree((u8 *)(info->MS_Lib.blkpag)); /* Arnold test ... */
+ info->MS_Lib.blkpag = NULL;
+ }
+
+ if (info->MS_Lib.blkext) {
+ kfree((u8 *)(info->MS_Lib.blkext)); /* Arnold test ... */
+ info->MS_Lib.blkext = NULL;
+ }
+}
+
+
+static void ms_lib_free_allocatedarea(struct us_data *us)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */
+ ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */
+
+ /* set struct us point flag to 0 */
+ info->MS_Lib.flags = 0;
+ info->MS_Lib.BytesPerSector = 0;
+ info->MS_Lib.SectorsPerCylinder = 0;
+
+ info->MS_Lib.cardType = 0;
+ info->MS_Lib.blockSize = 0;
+ info->MS_Lib.PagesPerBlock = 0;
+
+ info->MS_Lib.NumberOfPhyBlock = 0;
+ info->MS_Lib.NumberOfLogBlock = 0;
+}
+
+
+static int ms_lib_alloc_writebuf(struct us_data *us)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ info->MS_Lib.wrtblk = (u16)-1;
+
+ info->MS_Lib.blkpag = kmalloc(info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector, GFP_KERNEL);
+ info->MS_Lib.blkext = kmalloc(info->MS_Lib.PagesPerBlock * sizeof(struct ms_lib_type_extdat), GFP_KERNEL);
+
+ if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) {
+ ms_lib_free_writebuf(us);
+ return (u32)-1;
+ }
+
+ ms_lib_clear_writebuf(us);
+
+return 0;
+}
+
+static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (logblk == MS_LB_NOT_USED)
+ return 0;
+
+ if ((logblk >= info->MS_Lib.NumberOfLogBlock) ||
+ (phyblk >= info->MS_Lib.NumberOfPhyBlock))
+ return (u32)-1;
+
+ info->MS_Lib.Phy2LogMap[phyblk] = logblk;
+ info->MS_Lib.Log2PhyMap[logblk] = phyblk;
+
+ return 0;
+}
+
+static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
+ u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+
+ /* printk(KERN_INFO "MS_ReaderCopyBlock --- PhyBlockAddr = %x,
+ PageNum = %x\n", PhyBlockAddr, PageNum); */
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200*len;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xF0;
+ bcb->CDB[1] = 0x08;
+ bcb->CDB[4] = (unsigned char)(oldphy);
+ bcb->CDB[3] = (unsigned char)(oldphy>>8);
+ bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */
+ bcb->CDB[7] = (unsigned char)(newphy);
+ bcb->CDB[6] = (unsigned char)(newphy>>8);
+ bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */
+ bcb->CDB[9] = (unsigned char)(PhyBlockAddr);
+ bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8);
+ bcb->CDB[10] = PageNum;
+
+ result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u32 bn = PhyBlockAddr;
+
+ /* printk(KERN_INFO "MS --- ms_read_eraseblock,
+ PhyBlockAddr = %x\n", PhyBlockAddr); */
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF2;
+ bcb->CDB[1] = 0x06;
+ bcb->CDB[4] = (unsigned char)(bn);
+ bcb->CDB[3] = (unsigned char)(bn>>8);
+ bcb->CDB[2] = (unsigned char)(bn>>16);
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock)
+{
+ unsigned char *PageBuf = NULL;
+ u16 result = MS_STATUS_SUCCESS;
+ u16 blk, index = 0;
+ struct ms_lib_type_extdat extdat;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+ if (PageBuf == NULL) {
+ result = MS_NO_MEMORY_ERROR;
+ goto exit;
+ }
+
+ ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat);
+ do {
+ blk = be16_to_cpu(PageBuf[index]);
+ if (blk == MS_LB_NOT_USED)
+ break;
+ if (blk == info->MS_Lib.Log2PhyMap[0]) {
+ result = MS_ERROR_FLASH_READ;
+ break;
+ }
+ index++;
+ } while (1);
+
+exit:
+ kfree(PageBuf);
+ return result;
+}
+
+static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk)
+{
+ u16 log;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+ return (u32)-1;
+
+ log = info->MS_Lib.Phy2LogMap[phyblk];
+
+ if (log < info->MS_Lib.NumberOfLogBlock)
+ info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
+
+ if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR)
+ info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR;
+
+ return 0;
+}
+
+static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
+ u8 PageNum, u8 OverwriteFlag)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+
+ /* printk("MS --- MS_LibOverwriteExtra,
+ PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x4;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF2;
+ bcb->CDB[1] = 0x05;
+ bcb->CDB[5] = (unsigned char)(PageNum);
+ bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
+ bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
+ bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
+ bcb->CDB[6] = OverwriteFlag;
+ bcb->CDB[7] = 0xFF;
+ bcb->CDB[8] = 0xFF;
+ bcb->CDB[9] = 0xFF;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+ return MS_STATUS_ERROR;
+
+ ms_lib_setacquired_errorblock(us, phyblk);
+
+ if (ms_lib_iswritable(info))
+ return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK));
+
+ return MS_STATUS_SUCCESS;
+}
+
+static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk)
+{
+ u16 log;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+ return MS_STATUS_ERROR;
+
+ log = info->MS_Lib.Phy2LogMap[phyblk];
+
+ if (log < info->MS_Lib.NumberOfLogBlock)
+ info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
+
+ info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED;
+
+ if (ms_lib_iswritable(info)) {
+ switch (ms_read_eraseblock(us, phyblk)) {
+ case MS_STATUS_SUCCESS:
+ info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED;
+ return MS_STATUS_SUCCESS;
+ case MS_ERROR_FLASH_ERASE:
+ case MS_STATUS_INT_ERROR:
+ ms_lib_error_phyblock(us, phyblk);
+ return MS_ERROR_FLASH_ERASE;
+ case MS_STATUS_ERROR:
+ default:
+ ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); /* MS_LibCtrlSet will used by ENE_MSInit ,need check, and why us to info*/
+ ms_lib_setacquired_errorblock(us, phyblk);
+ return MS_STATUS_ERROR;
+ }
+ }
+
+ ms_lib_setacquired_errorblock(us, phyblk);
+
+ return MS_STATUS_SUCCESS;
+}
+
+static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
+ u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u8 ExtBuf[4];
+
+ /* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x4;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+ bcb->CDB[5] = (unsigned char)(PageNum);
+ bcb->CDB[4] = (unsigned char)(PhyBlock);
+ bcb->CDB[3] = (unsigned char)(PhyBlock>>8);
+ bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
+ bcb->CDB[6] = 0x01;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ ExtraDat->reserved = 0;
+ ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */
+ ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */
+ ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */
+ ExtraDat->ovrflg = ExtBuf[0];
+ ExtraDat->mngflg = ExtBuf[1];
+ ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk)
+{
+ u16 Newblk;
+ u16 blk;
+ struct ms_lib_type_extdat extdat; /* need check */
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+
+ if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
+ return MS_LB_ERROR;
+
+ for (blk = phyblk + 1; blk != phyblk; blk++) {
+ if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0)
+ blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+
+ Newblk = info->MS_Lib.Phy2LogMap[blk];
+ if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) {
+ return blk;
+ } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) {
+ switch (ms_lib_read_extra(us, blk, 0, &extdat)) {
+ case MS_STATUS_SUCCESS:
+ case MS_STATUS_SUCCESS_WITH_ECC:
+ break;
+ case MS_NOCARD_ERROR:
+ return MS_NOCARD_ERROR;
+ case MS_STATUS_INT_ERROR:
+ return MS_LB_ERROR;
+ case MS_ERROR_FLASH_READ:
+ default:
+ ms_lib_setacquired_errorblock(us, blk);
+ continue;
+ } /* End switch */
+
+ if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
+ ms_lib_setacquired_errorblock(us, blk);
+ continue;
+ }
+
+ switch (ms_lib_erase_phyblock(us, blk)) {
+ case MS_STATUS_SUCCESS:
+ return blk;
+ case MS_STATUS_ERROR:
+ return MS_LB_ERROR;
+ case MS_ERROR_FLASH_ERASE:
+ default:
+ ms_lib_error_phyblock(us, blk);
+ break;
+ }
+ }
+ } /* End for */
+
+ return MS_LB_ERROR;
+}
+static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk)
+{
+ u16 phyblk;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ phyblk = ms_libconv_to_physical(info, logblk);
+ if (phyblk >= MS_LB_ERROR) {
+ if (logblk >= info->MS_Lib.NumberOfLogBlock)
+ return MS_LB_ERROR;
+
+ phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT;
+ phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+ phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1;
+ }
+
+ return ms_libsearch_block_from_physical(us, phyblk);
+}
+
+static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+ /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */
+ if (info->MS_Status.Insert && info->MS_Status.Ready) {
+ return USB_STOR_TRANSPORT_GOOD;
+ } else {
+ ene_ms_init(us);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
+{
+ /* pr_info("MS_SCSI_Inquiry\n"); */
+ unsigned char data_ptr[36] = {
+ 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
+ 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
+ 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30};
+
+ usb_stor_set_xfer_buf(data_ptr, 36, srb);
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+ unsigned char mediaNoWP[12] = {
+ 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+ unsigned char mediaWP[12] = {
+ 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
+
+ if (info->MS_Status.WtP)
+ usb_stor_set_xfer_buf(mediaWP, 12, srb);
+ else
+ usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
+{
+ u32 bl_num;
+ u16 bl_len;
+ unsigned int offset = 0;
+ unsigned char buf[8];
+ struct scatterlist *sg = NULL;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ usb_stor_dbg(us, "ms_scsi_read_capacity\n");
+ bl_len = 0x200;
+ if (info->MS_Status.IsMSPro)
+ bl_num = info->MSP_TotalBlock - 1;
+ else
+ bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1;
+
+ info->bl_num = bl_num;
+ usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+ usb_stor_dbg(us, "bl_num = %x\n", bl_num);
+
+ /*srb->request_bufflen = 8; */
+ buf[0] = (bl_num >> 24) & 0xff;
+ buf[1] = (bl_num >> 16) & 0xff;
+ buf[2] = (bl_num >> 8) & 0xff;
+ buf[3] = (bl_num >> 0) & 0xff;
+ buf[4] = (bl_len >> 24) & 0xff;
+ buf[5] = (bl_len >> 16) & 0xff;
+ buf[6] = (bl_len >> 8) & 0xff;
+ buf[7] = (bl_len >> 0) & 0xff;
+
+ usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde)
+{
+ PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+
+ if (PhyBlock) {
+ *LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
+ *LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
+ } else {
+ *LogStart = 0;
+ *LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/
+ }
+}
+
+static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
+ u8 PageNum, u8 blen, void *buf)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+
+ /* printk("MS_LibReadExtraBlock --- PhyBlock = %x,
+ PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen); */
+
+ /* Read Extra Data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x4 * blen;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+ bcb->CDB[5] = (unsigned char)(PageNum);
+ bcb->CDB[4] = (unsigned char)(PhyBlock);
+ bcb->CDB[3] = (unsigned char)(PhyBlock>>8);
+ bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
+ bcb->CDB[6] = blen;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
+{
+ u16 PhyBlock, newblk, i;
+ u16 LogStart, LogEnde;
+ struct ms_lib_type_extdat extdat;
+ u8 buf[0x200];
+ u32 count = 0, index = 0;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
+ ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
+
+ for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) {
+ switch (ms_libconv_to_logical(info, PhyBlock)) {
+ case MS_STATUS_ERROR:
+ continue;
+ default:
+ break;
+ }
+
+ if (count == PhyBlock) {
+ ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf);
+ count += 0x80;
+ }
+ index = (PhyBlock % 0x80) * 4;
+
+ extdat.ovrflg = buf[index];
+ extdat.mngflg = buf[index+1];
+ extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]);
+
+ if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
+ ms_lib_setacquired_errorblock(us, PhyBlock);
+ continue;
+ }
+
+ if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) {
+ ms_lib_erase_phyblock(us, PhyBlock);
+ continue;
+ }
+
+ if (extdat.logadr != MS_LB_NOT_USED) {
+ if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) {
+ ms_lib_erase_phyblock(us, PhyBlock);
+ continue;
+ }
+
+ newblk = ms_libconv_to_physical(info, extdat.logadr);
+
+ if (newblk != MS_LB_NOT_USED) {
+ if (extdat.logadr == 0) {
+ ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
+ if (ms_lib_check_disableblock(us, btBlk1st)) {
+ ms_lib_set_logicalpair(us, extdat.logadr, newblk);
+ continue;
+ }
+ }
+
+ ms_lib_read_extra(us, newblk, 0, &extdat);
+ if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) {
+ ms_lib_erase_phyblock(us, PhyBlock);
+ continue;
+ } else {
+ ms_lib_erase_phyblock(us, newblk);
+ }
+ }
+
+ ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
+ }
+ }
+ } /* End for ... */
+
+ return MS_STATUS_SUCCESS;
+}
+
+
+static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ unsigned char *cdb = srb->cmnd;
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
+ ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
+
+ if (bn > info->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (info->MS_Status.IsMSPro) {
+ result = ene_load_bincode(us, MSP_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = blenByte;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x02;
+ bcb->CDB[5] = (unsigned char)(bn);
+ bcb->CDB[4] = (unsigned char)(bn>>8);
+ bcb->CDB[3] = (unsigned char)(bn>>16);
+ bcb->CDB[2] = (unsigned char)(bn>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
+ } else {
+ void *buf;
+ int offset = 0;
+ u16 phyblk, logblk;
+ u8 PageNum;
+ u16 len;
+ u32 blkno;
+
+ buf = kmalloc(blenByte, GFP_KERNEL);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ pr_info("Load MS RW pattern Fail !!\n");
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto exit;
+ }
+
+ logblk = (u16)(bn / info->MS_Lib.PagesPerBlock);
+ PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
+
+ while (1) {
+ if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
+ len = info->MS_Lib.PagesPerBlock-PageNum;
+ else
+ len = blen;
+
+ phyblk = ms_libconv_to_physical(info, logblk);
+ blkno = phyblk * 0x20 + PageNum;
+
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200 * len;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x02;
+ bcb->CDB[5] = (unsigned char)(blkno);
+ bcb->CDB[4] = (unsigned char)(blkno>>8);
+ bcb->CDB[3] = (unsigned char)(blkno>>16);
+ bcb->CDB[2] = (unsigned char)(blkno>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0);
+ if (result != USB_STOR_XFER_GOOD) {
+ pr_info("MS_SCSI_Read --- result = %x\n", result);
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto exit;
+ }
+
+ blen -= len;
+ if (blen <= 0)
+ break;
+ logblk++;
+ PageNum = 0;
+ offset += MS_BYTES_PER_PAGE*len;
+ }
+ usb_stor_set_xfer_buf(buf, blenByte, srb);
+exit:
+ kfree(buf);
+ }
+ return result;
+}
+
+static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ unsigned char *cdb = srb->cmnd;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ u32 bn = ((cdb[2] << 24) & 0xff000000) |
+ ((cdb[3] << 16) & 0x00ff0000) |
+ ((cdb[4] << 8) & 0x0000ff00) |
+ ((cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
+
+ if (bn > info->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (info->MS_Status.IsMSPro) {
+ result = ene_load_bincode(us, MSP_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ pr_info("Load MSP RW pattern Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = blenByte;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xF0;
+ bcb->CDB[1] = 0x04;
+ bcb->CDB[5] = (unsigned char)(bn);
+ bcb->CDB[4] = (unsigned char)(bn>>8);
+ bcb->CDB[3] = (unsigned char)(bn>>16);
+ bcb->CDB[2] = (unsigned char)(bn>>24);
+
+ result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
+ } else {
+ void *buf;
+ int offset = 0;
+ u16 PhyBlockAddr;
+ u8 PageNum;
+ u16 len, oldphy, newphy;
+
+ buf = kmalloc(blenByte, GFP_KERNEL);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ usb_stor_set_xfer_buf(buf, blenByte, srb);
+
+ result = ene_load_bincode(us, MS_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ pr_info("Load MS RW pattern Fail !!\n");
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto exit;
+ }
+
+ PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock);
+ PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
+
+ while (1) {
+ if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
+ len = info->MS_Lib.PagesPerBlock-PageNum;
+ else
+ len = blen;
+
+ oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */
+ newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr);
+
+ result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len);
+
+ if (result != USB_STOR_XFER_GOOD) {
+ pr_info("MS_SCSI_Write --- result = %x\n", result);
+ result = USB_STOR_TRANSPORT_ERROR;
+ goto exit;
+ }
+
+ info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED;
+ ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy);
+
+ blen -= len;
+ if (blen <= 0)
+ break;
+ PhyBlockAddr++;
+ PageNum = 0;
+ offset += MS_BYTES_PER_PAGE*len;
+ }
+exit:
+ kfree(buf);
+ }
+ return result;
+}
+
+/*
+ * ENE MS Card
+ */
+
+static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x01;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xED;
+ bcb->CDB[2] = (unsigned char)(index>>8);
+ bcb->CDB[3] = (unsigned char)index;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
+ return result;
+}
+
+static int ene_get_card_status(struct us_data *us, u8 *buf)
+{
+ u16 tmpreg;
+ u32 reg4b;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ /*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/
+ reg4b = *(u32 *)&buf[0x18];
+ info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
+
+ tmpreg = (u16) reg4b;
+ reg4b = *(u32 *)(&buf[0x14]);
+ if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC)
+ info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
+
+ info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22);
+ info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07;
+ if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC)
+ info->HC_C_SIZE = *(u32 *)(&buf[0x100]);
+
+ if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) {
+ info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN);
+ info->SD_READ_BL_LEN = SD_BLOCK_LEN;
+ } else {
+ info->SD_Block_Mult = 1;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ene_load_bincode(struct us_data *us, unsigned char flag)
+{
+ int err;
+ char *fw_name = NULL;
+ unsigned char *buf = NULL;
+ const struct firmware *sd_fw = NULL;
+ int result = USB_STOR_TRANSPORT_ERROR;
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ if (info->BIN_FLAG == flag)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ switch (flag) {
+ /* For SD */
+ case SD_INIT1_PATTERN:
+ usb_stor_dbg(us, "SD_INIT1_PATTERN\n");
+ fw_name = SD_INIT1_FIRMWARE;
+ break;
+ case SD_INIT2_PATTERN:
+ usb_stor_dbg(us, "SD_INIT2_PATTERN\n");
+ fw_name = SD_INIT2_FIRMWARE;
+ break;
+ case SD_RW_PATTERN:
+ usb_stor_dbg(us, "SD_RW_PATTERN\n");
+ fw_name = SD_RW_FIRMWARE;
+ break;
+ /* For MS */
+ case MS_INIT_PATTERN:
+ usb_stor_dbg(us, "MS_INIT_PATTERN\n");
+ fw_name = MS_INIT_FIRMWARE;
+ break;
+ case MSP_RW_PATTERN:
+ usb_stor_dbg(us, "MSP_RW_PATTERN\n");
+ fw_name = MSP_RW_FIRMWARE;
+ break;
+ case MS_RW_PATTERN:
+ usb_stor_dbg(us, "MS_RW_PATTERN\n");
+ fw_name = MS_RW_FIRMWARE;
+ break;
+ default:
+ usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n");
+ goto nofw;
+ }
+
+ err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
+ if (err) {
+ usb_stor_dbg(us, "load firmware %s failed\n", fw_name);
+ goto nofw;
+ }
+ buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL);
+ if (buf == NULL)
+ goto nofw;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = sd_fw->size;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xEF;
+
+ result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+ info->BIN_FLAG = flag;
+ kfree(buf);
+
+nofw:
+ release_firmware(sd_fw);
+ return result;
+}
+
+static int ms_card_init(struct us_data *us)
+{
+ u32 result;
+ u16 TmpBlock;
+ unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL;
+ struct ms_lib_type_extdat extdat;
+ u16 btBlk1st, btBlk2nd;
+ u32 btBlk1stErred;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ printk(KERN_INFO "MS_CardInit start\n");
+
+ ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */
+
+ /* get two PageBuffer */
+ PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+ PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+ if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) {
+ result = MS_NO_MEMORY_ERROR;
+ goto exit;
+ }
+
+ btBlk1st = btBlk2nd = MS_LB_NOT_USED;
+ btBlk1stErred = 0;
+
+ for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) {
+
+ switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) {
+ case MS_STATUS_SUCCESS:
+ break;
+ case MS_STATUS_INT_ERROR:
+ break;
+ case MS_STATUS_ERROR:
+ default:
+ continue;
+ }
+
+ if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG)
+ continue;
+
+ if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) ||
+ (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) ||
+ (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) ||
+ (((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES))
+ continue;
+
+ if (btBlk1st != MS_LB_NOT_USED) {
+ btBlk2nd = TmpBlock;
+ break;
+ }
+
+ btBlk1st = TmpBlock;
+ memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE);
+ if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER))
+ btBlk1stErred = 1;
+ }
+
+ if (btBlk1st == MS_LB_NOT_USED) {
+ result = MS_STATUS_ERROR;
+ goto exit;
+ }
+
+ /* write protect */
+ if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON)
+ ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
+
+ result = MS_STATUS_ERROR;
+ /* 1st Boot Block */
+ if (btBlk1stErred == 0)
+ result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1);
+ /* 1st */
+ /* 2nd Boot Block */
+ if (result && (btBlk2nd != MS_LB_NOT_USED))
+ result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0);
+
+ if (result) {
+ result = MS_STATUS_ERROR;
+ goto exit;
+ }
+
+ for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++)
+ info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
+
+ info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK;
+
+ if (btBlk2nd != MS_LB_NOT_USED) {
+ for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++)
+ info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
+
+ info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK;
+ }
+
+ result = ms_lib_scan_logicalblocknumber(us, btBlk1st);
+ if (result)
+ goto exit;
+
+ for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT;
+ TmpBlock < info->MS_Lib.NumberOfPhyBlock;
+ TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) {
+ if (ms_count_freeblock(us, TmpBlock) == 0) {
+ ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
+ break;
+ }
+ }
+
+ /* write */
+ if (ms_lib_alloc_writebuf(us)) {
+ result = MS_NO_MEMORY_ERROR;
+ goto exit;
+ }
+
+ result = MS_STATUS_SUCCESS;
+
+exit:
+ kfree(PageBuffer1);
+ kfree(PageBuffer0);
+
+ printk(KERN_INFO "MS_CardInit end\n");
+ return result;
+}
+
+static int ene_ms_init(struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u8 buf[0x200];
+ u16 MSP_BlockSize, MSP_UserAreaBlocks;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ printk(KERN_INFO "transport --- ENE_MSInit\n");
+
+ /* the same part to test ENE */
+
+ result = ene_load_bincode(us, MS_INIT_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Load MS Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x01;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+ if (result != USB_STOR_XFER_GOOD) {
+ printk(KERN_ERR "Execution MS Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ /* the same part to test ENE */
+ info->MS_Status = *(struct MS_STATUS *)&buf[0];
+
+ if (info->MS_Status.Insert && info->MS_Status.Ready) {
+ printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert);
+ printk(KERN_INFO "Ready = %x\n", info->MS_Status.Ready);
+ printk(KERN_INFO "IsMSPro = %x\n", info->MS_Status.IsMSPro);
+ printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG);
+ printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
+ if (info->MS_Status.IsMSPro) {
+ MSP_BlockSize = (buf[6] << 8) | buf[7];
+ MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
+ info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
+ } else {
+ ms_card_init(us); /* Card is MS (to ms.c)*/
+ }
+ usb_stor_dbg(us, "MS Init Code OK !!\n");
+ } else {
+ usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int ene_sd_init(struct us_data *us)
+{
+ int result;
+ u8 buf[0x200];
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
+
+ usb_stor_dbg(us, "transport --- ENE_SDInit\n");
+ /* SD Init Part-1 */
+ result = ene_load_bincode(us, SD_INIT1_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF2;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* SD Init Part-2 */
+ result = ene_load_bincode(us, SD_INIT2_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = US_BULK_FLAG_IN;
+ bcb->CDB[0] = 0xF1;
+
+ result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ info->SD_Status = *(struct SD_STATUS *)&buf[0];
+ if (info->SD_Status.Insert && info->SD_Status.Ready) {
+ struct SD_STATUS *s = &info->SD_Status;
+
+ ene_get_card_status(us, (unsigned char *)&buf);
+ usb_stor_dbg(us, "Insert = %x\n", s->Insert);
+ usb_stor_dbg(us, "Ready = %x\n", s->Ready);
+ usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC);
+ usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity);
+ usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed);
+ usb_stor_dbg(us, "WtP = %x\n", s->WtP);
+ } else {
+ usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int ene_init(struct us_data *us)
+{
+ int result;
+ u8 misc_reg03 = 0;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+ result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (misc_reg03 & 0x01) {
+ if (!info->SD_Status.Ready) {
+ result = ene_sd_init(us);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+ if (misc_reg03 & 0x02) {
+ if (!info->MS_Status.Ready) {
+ result = ene_ms_init(us);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+ return result;
+}
+
+/*----- sd_scsi_irp() ---------*/
+static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
+
+ info->SrbStatus = SS_SUCCESS;
+ switch (srb->cmnd[0]) {
+ case TEST_UNIT_READY:
+ result = sd_scsi_test_unit_ready(us, srb);
+ break; /* 0x00 */
+ case INQUIRY:
+ result = sd_scsi_inquiry(us, srb);
+ break; /* 0x12 */
+ case MODE_SENSE:
+ result = sd_scsi_mode_sense(us, srb);
+ break; /* 0x1A */
+ /*
+ case START_STOP:
+ result = SD_SCSI_Start_Stop(us, srb);
+ break; //0x1B
+ */
+ case READ_CAPACITY:
+ result = sd_scsi_read_capacity(us, srb);
+ break; /* 0x25 */
+ case READ_10:
+ result = sd_scsi_read(us, srb);
+ break; /* 0x28 */
+ case WRITE_10:
+ result = sd_scsi_write(us, srb);
+ break; /* 0x2A */
+ default:
+ info->SrbStatus = SS_ILLEGAL_REQUEST;
+ result = USB_STOR_TRANSPORT_FAILED;
+ break;
+ }
+ return result;
+}
+
+/*
+ * ms_scsi_irp()
+ */
+static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
+ info->SrbStatus = SS_SUCCESS;
+ switch (srb->cmnd[0]) {
+ case TEST_UNIT_READY:
+ result = ms_scsi_test_unit_ready(us, srb);
+ break; /* 0x00 */
+ case INQUIRY:
+ result = ms_scsi_inquiry(us, srb);
+ break; /* 0x12 */
+ case MODE_SENSE:
+ result = ms_scsi_mode_sense(us, srb);
+ break; /* 0x1A */
+ case READ_CAPACITY:
+ result = ms_scsi_read_capacity(us, srb);
+ break; /* 0x25 */
+ case READ_10:
+ result = ms_scsi_read(us, srb);
+ break; /* 0x28 */
+ case WRITE_10:
+ result = ms_scsi_write(us, srb);
+ break; /* 0x2A */
+ default:
+ info->SrbStatus = SS_ILLEGAL_REQUEST;
+ result = USB_STOR_TRANSPORT_FAILED;
+ break;
+ }
+ return result;
+}
+
+static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int result = 0;
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+ /*US_DEBUG(usb_stor_show_command(us, srb)); */
+ scsi_set_resid(srb, 0);
+ if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
+ result = ene_init(us);
+ } else {
+ if (info->SD_Status.Ready)
+ result = sd_scsi_irp(us, srb);
+
+ if (info->MS_Status.Ready)
+ result = ms_scsi_irp(us, srb);
+ }
+ return 0;
+}
+
+
+static int ene_ub6250_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int result;
+ u8 misc_reg03 = 0;
+ struct us_data *us;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list);
+ if (result)
+ return result;
+
+ /* FIXME: where should the code alloc extra buf ? */
+ if (!us->extra) {
+ us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
+ if (!us->extra)
+ return -ENOMEM;
+ us->extra_destructor = ene_ub6250_info_destructor;
+ }
+
+ us->transport_name = "ene_ub6250";
+ us->transport = ene_transport;
+ us->max_lun = 0;
+
+ result = usb_stor_probe2(us);
+ if (result)
+ return result;
+
+ /* probe card type */
+ result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
+ if (result != USB_STOR_XFER_GOOD) {
+ usb_stor_disconnect(intf);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (!(misc_reg03 & 0x01)) {
+ pr_info("ums_eneub6250: The driver only supports SD/MS card. "
+ "To use SM card, please build driver/staging/keucr\n");
+ }
+
+ return result;
+}
+
+
+#ifdef CONFIG_PM
+
+static int ene_ub6250_resume(struct usb_interface *iface)
+{
+ u8 tmp = 0;
+ struct us_data *us = usb_get_intfdata(iface);
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+ mutex_lock(&us->dev_mutex);
+
+ if (us->suspend_resume_hook)
+ (us->suspend_resume_hook)(us, US_RESUME);
+
+ mutex_unlock(&us->dev_mutex);
+
+ info->Power_IsResum = true;
+ /*info->SD_Status.Ready = 0; */
+ info->SD_Status = *(struct SD_STATUS *)&tmp;
+ info->MS_Status = *(struct MS_STATUS *)&tmp;
+ info->SM_Status = *(struct SM_STATUS *)&tmp;
+
+ return 0;
+}
+
+static int ene_ub6250_reset_resume(struct usb_interface *iface)
+{
+ u8 tmp = 0;
+ struct us_data *us = usb_get_intfdata(iface);
+ struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
+
+ /* Report the reset to the SCSI core */
+ usb_stor_reset_resume(iface);
+
+ /* FIXME: Notify the subdrivers that they need to reinitialize
+ * the device */
+ info->Power_IsResum = true;
+ /*info->SD_Status.Ready = 0; */
+ info->SD_Status = *(struct SD_STATUS *)&tmp;
+ info->MS_Status = *(struct MS_STATUS *)&tmp;
+ info->SM_Status = *(struct SM_STATUS *)&tmp;
+
+ return 0;
+}
+
+#else
+
+#define ene_ub6250_resume NULL
+#define ene_ub6250_reset_resume NULL
+
+#endif
+
+static struct usb_driver ene_ub6250_driver = {
+ .name = "ums_eneub6250",
+ .probe = ene_ub6250_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = ene_ub6250_resume,
+ .reset_resume = ene_ub6250_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = ene_ub6250_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(ene_ub6250_driver);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 30e96050fe0..ef16068b708 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -1,7 +1,5 @@
/* Driver for Freecom USB/IDE adaptor
*
- * $Id: freecom.c,v 1.22 2002/04/22 03:39:43 mdharm Exp $
- *
* Freecom v0.1:
*
* First release
@@ -28,9 +26,7 @@
* (http://www.freecom.de/)
*/
-#include <linux/config.h>
-#include <linux/hdreg.h>
-
+#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -38,10 +34,13 @@
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "freecom.h"
+
+MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
+MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
+MODULE_LICENSE("GPL");
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void pdump (void *, int);
+static void pdump(struct us_data *us, void *ibuffer, int length);
#endif
/* Bits of HD_STATUS */
@@ -108,6 +107,47 @@ struct freecom_status {
#define FCM_PACKET_LENGTH 64
#define FCM_STATUS_PACKET_LENGTH 4
+static int init_freecom(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id freecom_usb_ids[] = {
+# include "unusual_freecom.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, freecom_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev freecom_unusual_dev_list[] = {
+# include "unusual_freecom.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
static int
freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
unsigned int ipipe, unsigned int opipe, int count)
@@ -121,21 +161,20 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
fxfr->Count = cpu_to_le32 (count);
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
- US_DEBUGP("Read data Freecom! (c=%d)\n", count);
+ usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("Freecom readdata transport error\n");
+ usb_stor_dbg(us, "Freecom readdata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
- US_DEBUGP("Start of read\n");
- result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
- count, srb->use_sg, &srb->resid);
- US_DEBUGP("freecom_readdata done!\n");
+ usb_stor_dbg(us, "Start of read\n");
+ result = usb_stor_bulk_srb(us, ipipe, srb);
+ usb_stor_dbg(us, "freecom_readdata done!\n");
if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
@@ -155,22 +194,21 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
fxfr->Count = cpu_to_le32 (count);
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
- US_DEBUGP("Write data Freecom! (c=%d)\n", count);
+ usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("Freecom writedata transport error\n");
+ usb_stor_dbg(us, "Freecom writedata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
- US_DEBUGP("Start of write\n");
- result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
- count, srb->use_sg, &srb->resid);
+ usb_stor_dbg(us, "Start of write\n");
+ result = usb_stor_bulk_srb(us, opipe, srb);
- US_DEBUGP("freecom_writedata done!\n");
+ usb_stor_dbg(us, "freecom_writedata done!\n");
if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
@@ -180,7 +218,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
* Transport for the Freecom USB/IDE adaptor.
*
*/
-int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
+static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct freecom_cb_wrap *fcb;
struct freecom_status *fst;
@@ -192,7 +230,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
fcb = (struct freecom_cb_wrap *) us->iobuf;
fst = (struct freecom_status *) us->iobuf;
- US_DEBUGP("Freecom TRANSPORT STARTED\n");
+ usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
/* Get handles for both transports. */
opipe = us->send_bulk_pipe;
@@ -204,7 +242,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
memcpy (fcb->Atapi, srb->cmnd, 12);
memset (fcb->Filler, 0, sizeof (fcb->Filler));
- US_DEBUG(pdump (srb->cmnd, 12));
+ US_DEBUG(pdump(us, srb->cmnd, 12));
/* Send it out. */
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
@@ -214,7 +252,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* USB land. It returns the status in its own registers, which
* come back in the bulk pipe. */
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("freecom transport error\n");
+ usb_stor_dbg(us, "freecom transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -222,23 +260,23 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* doesn't hurt us to always do it now. */
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_STATUS_PACKET_LENGTH, &partial);
- US_DEBUGP("foo Status result %d %u\n", result, partial);
+ usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
/* The firmware will time-out commands after 20 seconds. Some commands
* can legitimately take longer than this, so we use a different
* command that only waits for the interrupt and then sends status,
- * without having to send a new ATAPI command to the device.
+ * without having to send a new ATAPI command to the device.
*
* NOTE: There is some indication that a data transfer after a timeout
* may not work, but that is a condition that should never happen.
*/
while (fst->Status & FCM_STATUS_BUSY) {
- US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n");
- US_DEBUGP("fst->Status is %x\n", fst->Status);
+ usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
+ usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
/* Get the status again */
fcb->Type = FCM_PACKET_STATUS;
@@ -255,7 +293,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* registers, which come back in the bulk pipe.
*/
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("freecom transport error\n");
+ usb_stor_dbg(us, "freecom transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -263,43 +301,44 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_STATUS_PACKET_LENGTH, &partial);
- US_DEBUGP("bar Status result %d %u\n", result, partial);
+ usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
}
if (partial != 4)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & 1) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
/* The device might not have as much data available as we
* requested. If you ask for more than the device has, this reads
* and such will hang. */
- US_DEBUGP("Device indicates that it has %d bytes available\n",
- le16_to_cpu (fst->Count));
- US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
+ usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
+ le16_to_cpu(fst->Count));
+ usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
/* Find the length we desire to read. */
switch (srb->cmnd[0]) {
- case INQUIRY:
- case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
- case MODE_SENSE:
- case MODE_SENSE_10:
- length = le16_to_cpu(fst->Count);
- break;
- default:
- length = srb->request_bufflen;
+ case INQUIRY:
+ case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ length = le16_to_cpu(fst->Count);
+ break;
+ default:
+ length = scsi_bufflen(srb);
}
/* verify that this amount is legal */
- if (length > srb->request_bufflen) {
- length = srb->request_bufflen;
- US_DEBUGP("Truncating request to match buffer length: %d\n", length);
+ if (length > scsi_bufflen(srb)) {
+ length = scsi_bufflen(srb);
+ usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
+ length);
}
/* What we do now depends on what direction the data is supposed to
@@ -313,29 +352,29 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Make sure that the status indicates that the device
* wants data as well. */
if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
- US_DEBUGP("SCSI wants data, drive doesn't have any\n");
+ usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
return USB_STOR_TRANSPORT_FAILED;
}
result = freecom_readdata (srb, us, ipipe, opipe, length);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- US_DEBUGP("FCM: Waiting for status\n");
+ usb_stor_dbg(us, "Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
- US_DEBUGP("Drive seems still hungry\n");
+ usb_stor_dbg(us, "Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
- US_DEBUGP("Transfer happy\n");
+ usb_stor_dbg(us, "Transfer happy\n");
break;
case DMA_TO_DEVICE:
@@ -349,22 +388,22 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- US_DEBUGP("FCM: Waiting for status\n");
+ usb_stor_dbg(us, "Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
- US_DEBUGP("Drive seems still hungry\n");
+ usb_stor_dbg(us, "Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
- US_DEBUGP("Transfer happy\n");
+ usb_stor_dbg(us, "Transfer happy\n");
break;
@@ -374,9 +413,9 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
default:
/* should never hit here -- filtered in usb.c */
- US_DEBUGP ("freecom unimplemented direction: %d\n",
- us->srb->sc_data_direction);
- // Return fail, SCSI seems to handle this better.
+ usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
+ us->srb->sc_data_direction);
+ /* Return fail, SCSI seems to handle this better. */
return USB_STOR_TRANSPORT_FAILED;
break;
}
@@ -384,8 +423,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
-int
-freecom_init (struct us_data *us)
+static int init_freecom(struct us_data *us)
{
int result;
char *buffer = us->iobuf;
@@ -397,7 +435,7 @@ freecom_init (struct us_data *us)
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
buffer[32] = '\0';
- US_DEBUGP("String returned from FC init is: %s\n", buffer);
+ usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
/* Special thanks to the people at Freecom for providing me with
* this "magic sequence", which they use in their Windows and MacOS
@@ -408,7 +446,7 @@ freecom_init (struct us_data *us)
/* send reset */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
- US_DEBUGP("result from activate reset is %d\n", result);
+ usb_stor_dbg(us, "result from activate reset is %d\n", result);
/* wait 250ms */
mdelay(250);
@@ -416,7 +454,7 @@ freecom_init (struct us_data *us)
/* clear reset */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
- US_DEBUGP("result from clear reset is %d\n", result);
+ usb_stor_dbg(us, "result from clear reset is %d\n", result);
/* wait 3 seconds */
mdelay(3 * 1000);
@@ -424,7 +462,7 @@ freecom_init (struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
-int usb_stor_freecom_reset(struct us_data *us)
+static int usb_stor_freecom_reset(struct us_data *us)
{
printk (KERN_CRIT "freecom reset called\n");
@@ -433,7 +471,7 @@ int usb_stor_freecom_reset(struct us_data *us)
}
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void pdump (void *ibuffer, int length)
+static void pdump(struct us_data *us, void *ibuffer, int length)
{
static char line[80];
int offset = 0;
@@ -453,12 +491,11 @@ static void pdump (void *ibuffer, int length)
line[offset++] = '.';
}
line[offset] = 0;
- US_DEBUGP("%s\n", line);
+ usb_stor_dbg(us, "%s\n", line);
offset = 0;
}
offset += sprintf (line+offset, "%08x:", i);
- }
- else if ((i & 7) == 0) {
+ } else if ((i & 7) == 0) {
offset += sprintf (line+offset, " -");
}
offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
@@ -481,8 +518,43 @@ static void pdump (void *ibuffer, int length)
line[offset++] = '.';
}
line[offset] = 0;
- US_DEBUGP("%s\n", line);
+ usb_stor_dbg(us, "%s\n", line);
offset = 0;
}
#endif
+static int freecom_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - freecom_usb_ids) + freecom_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "Freecom";
+ us->transport = freecom_transport;
+ us->transport_reset = usb_stor_freecom_reset;
+ us->max_lun = 0;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver freecom_driver = {
+ .name = "ums-freecom",
+ .probe = freecom_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = freecom_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(freecom_driver);
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 5b06f9240d0..5a8b5ff1e45 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -1,7 +1,5 @@
/* Special Initializers for certain USB Mass Storage devices
*
- * $Id: initializers.c,v 1.2 2000/09/06 22:35:57 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -37,7 +35,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include "usb.h"
@@ -51,12 +48,12 @@ int usb_stor_euscsi_init(struct us_data *us)
{
int result;
- US_DEBUGP("Attempting to init eUSCSI bridge...\n");
+ usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n");
us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
- 0x01, 0x0, us->iobuf, 0x1, 5*HZ);
- US_DEBUGP("-- result is %d\n", result);
+ 0x01, 0x0, us->iobuf, 0x1, 5000);
+ usb_stor_dbg(us, "-- result is %d\n", result);
return 0;
}
@@ -67,10 +64,11 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
- int res, partial;
+ int res;
+ unsigned int partial;
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
- US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
+ usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n");
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->Tag = 0;
@@ -82,12 +80,27 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
US_BULK_CB_WRAP_LEN, &partial);
- if(res)
- return res;
+ if (res)
+ return -EIO;
- US_DEBUGP("Getting status packet...\n");
+ usb_stor_dbg(us, "Getting status packet...\n");
res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &partial);
+ if (res)
+ return -EIO;
- return (res ? -1 : 0);
+ return 0;
+}
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+ int result;
+
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ USB_REQ_SET_FEATURE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 0x01, 0x0, NULL, 0x0, 1000);
+ usb_stor_dbg(us, "Huawei mode set result is %d\n", result);
+ return 0;
}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index 7372386f33d..529327fbb06 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -1,7 +1,5 @@
/* Header file for Special Initializers for certain USB Mass Storage devices
*
- * $Id: initializers.h,v 1.1 2000/08/29 23:07:02 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -37,7 +35,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include "usb.h"
#include "transport.h"
@@ -45,10 +42,9 @@
* mode */
int usb_stor_euscsi_init(struct us_data *us);
-#ifdef CONFIG_USB_STORAGE_SDDR09
-int sddr09_init(struct us_data *us);
-#endif
-
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index ecb328aa9ea..599d8bff26c 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1,9 +1,7 @@
/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
*
- * $Id: isd200.c,v 1.16 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance:
- * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
+ * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
*
* Developed with the assistance of:
* (C) 2002 Alan Stern <stern@rowland.org>
@@ -46,9 +44,11 @@
#include <linux/jiffies.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/ata.h>
#include <linux/hdreg.h>
-#include <linux/ide.h>
+#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -59,8 +59,51 @@
#include "protocol.h"
#include "debug.h"
#include "scsiglue.h"
-#include "isd200.h"
+MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC");
+MODULE_AUTHOR("Björn Stenberg <bjorn@haxx.se>");
+MODULE_LICENSE("GPL");
+
+static int isd200_Initialization(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id isd200_usb_ids[] = {
+# include "unusual_isd200.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, isd200_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev isd200_unusual_dev_list[] = {
+# include "unusual_isd200.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
/* Timeout defines (in Seconds) */
@@ -109,6 +152,12 @@
#define REG_STATUS 0x80
#define REG_COMMAND 0x80
+/* ATA registers offset definitions */
+#define ATA_REG_ERROR_OFFSET 1
+#define ATA_REG_LCYL_OFFSET 4
+#define ATA_REG_HCYL_OFFSET 5
+#define ATA_REG_STATUS_OFFSET 7
+
/* ATA error definitions not in <linux/hdreg.h> */
#define ATA_ERROR_MEDIA_CHANGE 0x20
@@ -277,7 +326,7 @@ struct isd200_config {
struct isd200_info {
struct inquiry_data InquiryData;
- struct hd_driveid *id;
+ u16 *id;
struct isd200_config ConfigData;
unsigned char *RegsBuf;
unsigned char ATARegs[8];
@@ -286,7 +335,9 @@ struct isd200_info {
/* maximum number of LUNs supported */
unsigned char MaxLUNs;
+ unsigned char cmnd[BLK_MAX_CDB];
struct scsi_cmnd srb;
+ struct scatterlist sg;
};
@@ -358,7 +409,7 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
{
struct isd200_info *info = (struct isd200_info *)us->extra;
struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
- unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+ unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET];
if(error & ATA_ERROR_MEDIA_CHANGE) {
buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
@@ -366,19 +417,19 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
buf->Flags = UNIT_ATTENTION;
buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0;
- } else if(error & MCR_ERR) {
+ } else if (error & ATA_MCR) {
buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->AdditionalSenseLength = 0xb;
buf->Flags = UNIT_ATTENTION;
buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0;
- } else if(error & TRK0_ERR) {
+ } else if (error & ATA_TRK0NF) {
buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->AdditionalSenseLength = 0xb;
buf->Flags = NOT_READY;
buf->AdditionalSenseCode = 0;
buf->AdditionalSenseCodeQualifier = 0;
- } else if(error & ECC_ERR) {
+ } else if (error & ATA_UNC) {
buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
buf->AdditionalSenseLength = 0xb;
buf->Flags = DATA_PROTECT;
@@ -398,6 +449,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
* Transport routines
***********************************************************************/
+/**************************************************************************
+ * isd200_set_srb(), isd200_srb_set_bufflen()
+ *
+ * Two helpers to facilitate in initialization of scsi_cmnd structure
+ * Will need to change when struct scsi_cmnd changes
+ */
+static void isd200_set_srb(struct isd200_info *info,
+ enum dma_data_direction dir, void* buff, unsigned bufflen)
+{
+ struct scsi_cmnd *srb = &info->srb;
+
+ if (buff)
+ sg_init_one(&info->sg, buff, bufflen);
+
+ srb->sc_data_direction = dir;
+ srb->sdb.table.sgl = buff ? &info->sg : NULL;
+ srb->sdb.length = bufflen;
+ srb->sdb.table.nents = buff ? 1 : 0;
+}
+
+static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
+{
+ srb->sdb.length = bufflen;
+}
+
/**************************************************************************
* isd200_action
@@ -411,15 +487,15 @@ static int isd200_action( struct us_data *us, int action,
void* pointer, int value )
{
union ata_cdb ata;
- struct scsi_device srb_dev;
+ /* static to prevent this large struct being placed on the valuable stack */
+ static struct scsi_device srb_dev;
struct isd200_info *info = (struct isd200_info *)us->extra;
struct scsi_cmnd *srb = &info->srb;
int status;
memset(&ata, 0, sizeof(ata));
- memset(&srb_dev, 0, sizeof(srb_dev));
+ srb->cmnd = info->cmnd;
srb->device = &srb_dev;
- ++srb->serial_number;
ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -427,65 +503,62 @@ static int isd200_action( struct us_data *us, int action,
switch ( action ) {
case ACTION_READ_STATUS:
- US_DEBUGP(" isd200_action(READ_STATUS)\n");
+ usb_stor_dbg(us, " isd200_action(READ_STATUS)\n");
ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
ata.generic.RegisterSelect =
REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
REG_STATUS | REG_ERROR;
- srb->sc_data_direction = DMA_FROM_DEVICE;
- srb->request_buffer = pointer;
- srb->request_bufflen = value;
+ isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
break;
case ACTION_ENUM:
- US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value);
+ usb_stor_dbg(us, " isd200_action(ENUM,0x%02x)\n", value);
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4|
ACTION_SELECT_5;
ata.generic.RegisterSelect = REG_DEVICE_HEAD;
ata.write.DeviceHeadByte = value;
- srb->sc_data_direction = DMA_NONE;
+ isd200_set_srb(info, DMA_NONE, NULL, 0);
break;
case ACTION_RESET:
- US_DEBUGP(" isd200_action(RESET)\n");
+ usb_stor_dbg(us, " isd200_action(RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4;
ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
- srb->sc_data_direction = DMA_NONE;
+ isd200_set_srb(info, DMA_NONE, NULL, 0);
break;
case ACTION_REENABLE:
- US_DEBUGP(" isd200_action(REENABLE)\n");
+ usb_stor_dbg(us, " isd200_action(REENABLE)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4;
ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
- srb->sc_data_direction = DMA_NONE;
+ isd200_set_srb(info, DMA_NONE, NULL, 0);
break;
case ACTION_SOFT_RESET:
- US_DEBUGP(" isd200_action(SOFT_RESET)\n");
+ usb_stor_dbg(us, " isd200_action(SOFT_RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
ata.write.DeviceHeadByte = info->DeviceHead;
- ata.write.CommandByte = WIN_SRST;
- srb->sc_data_direction = DMA_NONE;
+ ata.write.CommandByte = ATA_CMD_DEV_RESET;
+ isd200_set_srb(info, DMA_NONE, NULL, 0);
break;
case ACTION_IDENTIFY:
- US_DEBUGP(" isd200_action(IDENTIFY)\n");
+ usb_stor_dbg(us, " isd200_action(IDENTIFY)\n");
ata.generic.RegisterSelect = REG_COMMAND;
- ata.write.CommandByte = WIN_IDENTIFY;
- srb->sc_data_direction = DMA_FROM_DEVICE;
- srb->request_buffer = (void *) info->id;
- srb->request_bufflen = sizeof(struct hd_driveid);
+ ata.write.CommandByte = ATA_CMD_ID_ATA;
+ isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
+ ATA_ID_WORDS * 2);
break;
default:
- US_DEBUGP("Error: Undefined action %d\n",action);
- break;
+ usb_stor_dbg(us, "Error: Undefined action %d\n", action);
+ return ISD200_ERROR;
}
memcpy(srb->cmnd, &ata, sizeof(ata.generic));
@@ -494,7 +567,8 @@ static int isd200_action( struct us_data *us, int action,
if (status == USB_STOR_TRANSPORT_GOOD)
status = ISD200_GOOD;
else {
- US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status);
+ usb_stor_dbg(us, " isd200_action(0x%02x) error: %d\n",
+ action, status);
status = ISD200_ERROR;
/* need to reset device here */
}
@@ -516,17 +590,17 @@ static int isd200_read_regs( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_IssueATAReadRegs\n");
+ usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n");
transferStatus = isd200_action( us, ACTION_READ_STATUS,
info->RegsBuf, sizeof(info->ATARegs) );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error reading ATA registers\n");
+ usb_stor_dbg(us, " Error reading ATA registers\n");
retStatus = ISD200_ERROR;
} else {
memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
- US_DEBUGP(" Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n",
- info->ATARegs[IDE_ERROR_OFFSET]);
+ usb_stor_dbg(us, " Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
+ info->ATARegs[ATA_REG_ERROR_OFFSET]);
}
return retStatus;
@@ -555,8 +629,8 @@ static void isd200_invoke_transport( struct us_data *us,
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
- US_DEBUGP("-- command was aborted\n");
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ usb_stor_dbg(us, "-- command was aborted\n");
goto Handle_Abort;
}
@@ -568,42 +642,42 @@ static void isd200_invoke_transport( struct us_data *us,
break;
case USB_STOR_TRANSPORT_NO_SENSE:
- US_DEBUGP("-- transport indicates protocol failure\n");
+ usb_stor_dbg(us, "-- transport indicates protocol failure\n");
srb->result = SAM_STAT_CHECK_CONDITION;
return;
case USB_STOR_TRANSPORT_FAILED:
- US_DEBUGP("-- transport indicates command failure\n");
+ usb_stor_dbg(us, "-- transport indicates command failure\n");
need_auto_sense = 1;
break;
case USB_STOR_TRANSPORT_ERROR:
- US_DEBUGP("-- transport indicates transport error\n");
+ usb_stor_dbg(us, "-- transport indicates transport error\n");
srb->result = DID_ERROR << 16;
/* Need reset here */
return;
default:
- US_DEBUGP("-- transport indicates unknown error\n");
+ usb_stor_dbg(us, "-- transport indicates unknown error\n");
srb->result = DID_ERROR << 16;
/* Need reset here */
return;
}
- if ((srb->resid > 0) &&
+ if ((scsi_get_resid(srb) > 0) &&
!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
- US_DEBUGP("-- unexpectedly short transfer\n");
+ usb_stor_dbg(us, "-- unexpectedly short transfer\n");
need_auto_sense = 1;
}
if (need_auto_sense) {
result = isd200_read_regs(us);
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
- US_DEBUGP("-- auto-sense aborted\n");
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ usb_stor_dbg(us, "-- auto-sense aborted\n");
goto Handle_Abort;
}
if (result == ISD200_GOOD) {
@@ -632,45 +706,45 @@ static void isd200_invoke_transport( struct us_data *us,
srb->result = DID_ABORT << 16;
/* permit the reset transfer to take place */
- clear_bit(US_FLIDX_ABORTING, &us->flags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
/* Need reset here */
}
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void isd200_log_config( struct isd200_info* info )
+static void isd200_log_config(struct us_data *us, struct isd200_info *info)
{
- US_DEBUGP(" Event Notification: 0x%x\n",
- info->ConfigData.EventNotification);
- US_DEBUGP(" External Clock: 0x%x\n",
- info->ConfigData.ExternalClock);
- US_DEBUGP(" ATA Init Timeout: 0x%x\n",
- info->ConfigData.ATAInitTimeout);
- US_DEBUGP(" ATAPI Command Block Size: 0x%x\n",
- (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
- US_DEBUGP(" Master/Slave Selection: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_MASTER);
- US_DEBUGP(" ATAPI Reset: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
- US_DEBUGP(" ATA Timing: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_TIMING);
- US_DEBUGP(" ATA Major Command: 0x%x\n",
- info->ConfigData.ATAMajorCommand);
- US_DEBUGP(" ATA Minor Command: 0x%x\n",
- info->ConfigData.ATAMinorCommand);
- US_DEBUGP(" Init Status: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
- US_DEBUGP(" Config Descriptor 2: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
- US_DEBUGP(" Skip Device Boot: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
- US_DEBUGP(" ATA 3 State Supsend: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
- US_DEBUGP(" Descriptor Override: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
- US_DEBUGP(" Last LUN Identifier: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
- US_DEBUGP(" SRST Enable: 0x%x\n",
- info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
+ usb_stor_dbg(us, " Event Notification: 0x%x\n",
+ info->ConfigData.EventNotification);
+ usb_stor_dbg(us, " External Clock: 0x%x\n",
+ info->ConfigData.ExternalClock);
+ usb_stor_dbg(us, " ATA Init Timeout: 0x%x\n",
+ info->ConfigData.ATAInitTimeout);
+ usb_stor_dbg(us, " ATAPI Command Block Size: 0x%x\n",
+ (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
+ usb_stor_dbg(us, " Master/Slave Selection: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_MASTER);
+ usb_stor_dbg(us, " ATAPI Reset: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
+ usb_stor_dbg(us, " ATA Timing: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_TIMING);
+ usb_stor_dbg(us, " ATA Major Command: 0x%x\n",
+ info->ConfigData.ATAMajorCommand);
+ usb_stor_dbg(us, " ATA Minor Command: 0x%x\n",
+ info->ConfigData.ATAMinorCommand);
+ usb_stor_dbg(us, " Init Status: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
+ usb_stor_dbg(us, " Config Descriptor 2: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
+ usb_stor_dbg(us, " Skip Device Boot: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
+ usb_stor_dbg(us, " ATA 3 State Supsend: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
+ usb_stor_dbg(us, " Descriptor Override: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
+ usb_stor_dbg(us, " Last LUN Identifier: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
+ usb_stor_dbg(us, " SRST Enable: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
}
#endif
@@ -689,9 +763,9 @@ static int isd200_write_config( struct us_data *us )
int result;
#ifdef CONFIG_USB_STORAGE_DEBUG
- US_DEBUGP("Entering isd200_write_config\n");
- US_DEBUGP(" Writing the following ISD200 Config Data:\n");
- isd200_log_config(info);
+ usb_stor_dbg(us, "Entering isd200_write_config\n");
+ usb_stor_dbg(us, " Writing the following ISD200 Config Data:\n");
+ isd200_log_config(us, info);
#endif
/* let's send the command via the control pipe */
@@ -706,13 +780,13 @@ static int isd200_write_config( struct us_data *us )
sizeof(info->ConfigData));
if (result >= 0) {
- US_DEBUGP(" ISD200 Config Data was written successfully\n");
+ usb_stor_dbg(us, " ISD200 Config Data was written successfully\n");
} else {
- US_DEBUGP(" Request to write ISD200 Config Data failed!\n");
+ usb_stor_dbg(us, " Request to write ISD200 Config Data failed!\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus);
return retStatus;
}
@@ -731,7 +805,7 @@ static int isd200_read_config( struct us_data *us )
int retStatus = ISD200_GOOD;
int result;
- US_DEBUGP("Entering isd200_read_config\n");
+ usb_stor_dbg(us, "Entering isd200_read_config\n");
/* read the configuration information from ISD200. Use this to */
/* determine what the special ATA CDB bytes are. */
@@ -748,16 +822,16 @@ static int isd200_read_config( struct us_data *us )
if (result >= 0) {
- US_DEBUGP(" Retrieved the following ISD200 Config Data:\n");
+ usb_stor_dbg(us, " Retrieved the following ISD200 Config Data:\n");
#ifdef CONFIG_USB_STORAGE_DEBUG
- isd200_log_config(info);
+ isd200_log_config(us, info);
#endif
} else {
- US_DEBUGP(" Request to get ISD200 Config Data failed!\n");
+ usb_stor_dbg(us, " Request to get ISD200 Config Data failed!\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus);
return retStatus;
}
@@ -775,15 +849,15 @@ static int isd200_atapi_soft_reset( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_atapi_soft_reset\n");
+ usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n");
transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error issuing Atapi Soft Reset\n");
+ usb_stor_dbg(us, " Error issuing Atapi Soft Reset\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus);
return retStatus;
}
@@ -801,13 +875,13 @@ static int isd200_srst( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_SRST\n");
+ usb_stor_dbg(us, "Entering isd200_SRST\n");
transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 );
/* check to see if this request failed */
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error issuing SRST\n");
+ usb_stor_dbg(us, " Error issuing SRST\n");
retStatus = ISD200_ERROR;
} else {
/* delay 10ms to give the drive a chance to see it */
@@ -815,7 +889,7 @@ static int isd200_srst( struct us_data *us )
transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error taking drive out of reset\n");
+ usb_stor_dbg(us, " Error taking drive out of reset\n");
retStatus = ISD200_ERROR;
} else {
/* delay 50ms to give the drive a chance to recover after SRST */
@@ -823,7 +897,7 @@ static int isd200_srst( struct us_data *us )
}
}
- US_DEBUGP("Leaving isd200_srst %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus);
return retStatus;
}
@@ -853,10 +927,6 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
/* loop until we detect !BSY or timeout */
while(1) {
-#ifdef CONFIG_USB_STORAGE_DEBUG
- char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ?
- "Master" : "Slave";
-#endif
status = isd200_action( us, ACTION_ENUM, NULL, master_slave );
if ( status != ISD200_GOOD )
@@ -868,23 +938,27 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
break;
if (!detect) {
- if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
- US_DEBUGP(" %s status is still BSY, try again...\n",mstr);
+ if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) {
+ usb_stor_dbg(us, " %s status is still BSY, try again...\n",
+ master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+ "Master" : "Slave");
} else {
- US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr);
+ usb_stor_dbg(us, " %s status !BSY, continue with next operation\n",
+ master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+ "Master" : "Slave");
break;
}
}
- /* check for BUSY_STAT and */
- /* WRERR_STAT (workaround ATA Zip drive) and */
- /* ERR_STAT (workaround for Archos CD-ROM) */
- else if (regs[IDE_STATUS_OFFSET] &
- (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
- US_DEBUGP(" Status indicates it is not ready, try again...\n");
+ /* check for ATA_BUSY and */
+ /* ATA_DF (workaround ATA Zip drive) and */
+ /* ATA_ERR (workaround for Archos CD-ROM) */
+ else if (regs[ATA_REG_STATUS_OFFSET] &
+ (ATA_BUSY | ATA_DF | ATA_ERR)) {
+ usb_stor_dbg(us, " Status indicates it is not ready, try again...\n");
}
/* check for DRDY, ATA devices set DRDY after SRST */
- else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
- US_DEBUGP(" Identified ATA device\n");
+ else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) {
+ usb_stor_dbg(us, " Identified ATA device\n");
info->DeviceFlags |= DF_ATA_DEVICE;
info->DeviceHead = master_slave;
break;
@@ -892,8 +966,8 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
/* check Cylinder High/Low to
determine if it is an ATAPI device
*/
- else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
- (regs[IDE_LCYL_OFFSET] == 0x14)) {
+ else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
+ regs[ATA_REG_LCYL_OFFSET] == 0x14) {
/* It seems that the RICOH
MP6200A CD/RW drive will
report itself okay as a
@@ -905,27 +979,27 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
*/
if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
!recheckAsMaster) {
- US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n");
+ usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n");
recheckAsMaster = 1;
master_slave = ATA_ADDRESS_DEVHEAD_STD;
} else {
- US_DEBUGP(" Identified ATAPI device\n");
+ usb_stor_dbg(us, " Identified ATAPI device\n");
info->DeviceHead = master_slave;
status = isd200_atapi_soft_reset(us);
break;
}
} else {
- US_DEBUGP(" Not ATA, not ATAPI. Weird.\n");
+ usb_stor_dbg(us, " Not ATA, not ATAPI - Weird\n");
break;
}
/* check for timeout on this request */
if (time_after_eq(jiffies, endTime)) {
if (!detect)
- US_DEBUGP(" BSY check timeout, just continue with next operation...\n");
+ usb_stor_dbg(us, " BSY check timeout, just continue with next operation...\n");
else
- US_DEBUGP(" Device detect timeout!\n");
+ usb_stor_dbg(us, " Device detect timeout!\n");
break;
}
}
@@ -947,7 +1021,7 @@ static int isd200_manual_enum(struct us_data *us)
struct isd200_info *info = (struct isd200_info *)us->extra;
int retStatus = ISD200_GOOD;
- US_DEBUGP("Entering isd200_manual_enum\n");
+ usb_stor_dbg(us, "Entering isd200_manual_enum\n");
retStatus = isd200_read_config(us);
if (retStatus == ISD200_GOOD) {
@@ -966,17 +1040,62 @@ static int isd200_manual_enum(struct us_data *us)
isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) {
- US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave);
+ usb_stor_dbg(us, " Setting Master/Slave selection to %d\n",
+ isslave);
info->ConfigData.ATAConfig &= 0x3f;
info->ConfigData.ATAConfig |= (isslave<<6);
retStatus = isd200_write_config(us);
}
}
- US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus);
return(retStatus);
}
+static void isd200_fix_driveid(u16 *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+ int i;
+
+ for (i = 0; i < ATA_ID_WORDS; i++)
+ id[i] = __le16_to_cpu(id[i]);
+# else
+# error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+static void isd200_dump_driveid(struct us_data *us, u16 *id)
+{
+ usb_stor_dbg(us, " Identify Data Structure:\n");
+ usb_stor_dbg(us, " config = 0x%x\n", id[ATA_ID_CONFIG]);
+ usb_stor_dbg(us, " cyls = 0x%x\n", id[ATA_ID_CYLS]);
+ usb_stor_dbg(us, " heads = 0x%x\n", id[ATA_ID_HEADS]);
+ usb_stor_dbg(us, " track_bytes = 0x%x\n", id[4]);
+ usb_stor_dbg(us, " sector_bytes = 0x%x\n", id[5]);
+ usb_stor_dbg(us, " sectors = 0x%x\n", id[ATA_ID_SECTORS]);
+ usb_stor_dbg(us, " serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]);
+ usb_stor_dbg(us, " buf_type = 0x%x\n", id[20]);
+ usb_stor_dbg(us, " buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]);
+ usb_stor_dbg(us, " ecc_bytes = 0x%x\n", id[22]);
+ usb_stor_dbg(us, " fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]);
+ usb_stor_dbg(us, " model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]);
+ usb_stor_dbg(us, " max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff);
+ usb_stor_dbg(us, " dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]);
+ usb_stor_dbg(us, " capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8);
+ usb_stor_dbg(us, " tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8);
+ usb_stor_dbg(us, " tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8);
+ usb_stor_dbg(us, " field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]);
+ usb_stor_dbg(us, " cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]);
+ usb_stor_dbg(us, " cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]);
+ usb_stor_dbg(us, " cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]);
+ usb_stor_dbg(us, " cur_capacity = 0x%x\n", ata_id_u32(id, 57));
+ usb_stor_dbg(us, " multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff);
+ usb_stor_dbg(us, " lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY));
+ usb_stor_dbg(us, " command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]);
+ usb_stor_dbg(us, " command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]);
+}
/**************************************************************************
* isd200_get_inquiry_data
@@ -990,9 +1109,9 @@ static int isd200_get_inquiry_data( struct us_data *us )
{
struct isd200_info *info = (struct isd200_info *)us->extra;
int retStatus = ISD200_GOOD;
- struct hd_driveid *id = info->id;
+ u16 *id = info->id;
- US_DEBUGP("Entering isd200_get_inquiry_data\n");
+ usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n");
/* set default to Master */
info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
@@ -1007,46 +1126,19 @@ static int isd200_get_inquiry_data( struct us_data *us )
/* this must be an ATA device */
/* perform an ATA Command Identify */
transferStatus = isd200_action( us, ACTION_IDENTIFY,
- id,
- sizeof(struct hd_driveid) );
+ id, ATA_ID_WORDS * 2);
if (transferStatus != ISD200_TRANSPORT_GOOD) {
/* Error issuing ATA Command Identify */
- US_DEBUGP(" Error issuing ATA Command Identify\n");
+ usb_stor_dbg(us, " Error issuing ATA Command Identify\n");
retStatus = ISD200_ERROR;
} else {
/* ATA Command Identify successful */
int i;
__be16 *src;
__u16 *dest;
- ide_fix_driveid(id);
-
- US_DEBUGP(" Identify Data Structure:\n");
- US_DEBUGP(" config = 0x%x\n", id->config);
- US_DEBUGP(" cyls = 0x%x\n", id->cyls);
- US_DEBUGP(" heads = 0x%x\n", id->heads);
- US_DEBUGP(" track_bytes = 0x%x\n", id->track_bytes);
- US_DEBUGP(" sector_bytes = 0x%x\n", id->sector_bytes);
- US_DEBUGP(" sectors = 0x%x\n", id->sectors);
- US_DEBUGP(" serial_no[0] = 0x%x\n", id->serial_no[0]);
- US_DEBUGP(" buf_type = 0x%x\n", id->buf_type);
- US_DEBUGP(" buf_size = 0x%x\n", id->buf_size);
- US_DEBUGP(" ecc_bytes = 0x%x\n", id->ecc_bytes);
- US_DEBUGP(" fw_rev[0] = 0x%x\n", id->fw_rev[0]);
- US_DEBUGP(" model[0] = 0x%x\n", id->model[0]);
- US_DEBUGP(" max_multsect = 0x%x\n", id->max_multsect);
- US_DEBUGP(" dword_io = 0x%x\n", id->dword_io);
- US_DEBUGP(" capability = 0x%x\n", id->capability);
- US_DEBUGP(" tPIO = 0x%x\n", id->tPIO);
- US_DEBUGP(" tDMA = 0x%x\n", id->tDMA);
- US_DEBUGP(" field_valid = 0x%x\n", id->field_valid);
- US_DEBUGP(" cur_cyls = 0x%x\n", id->cur_cyls);
- US_DEBUGP(" cur_heads = 0x%x\n", id->cur_heads);
- US_DEBUGP(" cur_sectors = 0x%x\n", id->cur_sectors);
- US_DEBUGP(" cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 );
- US_DEBUGP(" multsect = 0x%x\n", id->multsect);
- US_DEBUGP(" lba_capacity = 0x%x\n", id->lba_capacity);
- US_DEBUGP(" command_set_1 = 0x%x\n", id->command_set_1);
- US_DEBUGP(" command_set_2 = 0x%x\n", id->command_set_2);
+
+ isd200_fix_driveid(id);
+ isd200_dump_driveid(us, id);
memset(&info->InquiryData, 0, sizeof(info->InquiryData));
@@ -1056,31 +1148,31 @@ static int isd200_get_inquiry_data( struct us_data *us )
/* The length must be at least 36 (5 + 31) */
info->InquiryData.AdditionalLength = 0x1F;
- if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) {
+ if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) {
/* set the removable bit */
info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
info->DeviceFlags |= DF_REMOVABLE_MEDIA;
}
/* Fill in vendor identification fields */
- src = (__be16*)id->model;
+ src = (__be16 *)&id[ATA_ID_PROD];
dest = (__u16*)info->InquiryData.VendorId;
for (i=0;i<4;i++)
dest[i] = be16_to_cpu(src[i]);
- src = (__be16*)(id->model+8);
+ src = (__be16 *)&id[ATA_ID_PROD + 8/2];
dest = (__u16*)info->InquiryData.ProductId;
for (i=0;i<8;i++)
dest[i] = be16_to_cpu(src[i]);
- src = (__be16*)id->fw_rev;
+ src = (__be16 *)&id[ATA_ID_FW_REV];
dest = (__u16*)info->InquiryData.ProductRevisionLevel;
for (i=0;i<2;i++)
dest[i] = be16_to_cpu(src[i]);
/* determine if it supports Media Status Notification */
- if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) {
- US_DEBUGP(" Device supports Media Status Notification\n");
+ if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) {
+ usb_stor_dbg(us, " Device supports Media Status Notification\n");
/* Indicate that it is enabled, even though it is not
* This allows the lock/unlock of the media to work
@@ -1100,21 +1192,22 @@ static int isd200_get_inquiry_data( struct us_data *us )
us->protocol_name = "Transparent SCSI";
us->proto_handler = usb_stor_transparent_scsi_command;
- US_DEBUGP("Protocol changed to: %s\n", us->protocol_name);
+ usb_stor_dbg(us, "Protocol changed to: %s\n",
+ us->protocol_name);
/* Free driver structure */
us->extra_destructor(info);
+ kfree(info);
us->extra = NULL;
us->extra_destructor = NULL;
}
}
- US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus);
return(retStatus);
}
-
/**************************************************************************
* isd200_scsi_to_ata
*
@@ -1128,7 +1221,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
union ata_cdb * ataCdb)
{
struct isd200_info *info = (struct isd200_info *)us->extra;
- struct hd_driveid *id = info->id;
+ u16 *id = info->id;
int sendToTransport = 1;
unsigned char sectnum, head;
unsigned short cylinder;
@@ -1141,7 +1234,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
/* SCSI Command */
switch (srb->cmnd[0]) {
case INQUIRY:
- US_DEBUGP(" ATA OUT - INQUIRY\n");
+ usb_stor_dbg(us, " ATA OUT - INQUIRY\n");
/* copy InquiryData */
usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData,
@@ -1151,7 +1244,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case MODE_SENSE:
- US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_MODE_SENSE\n");
/* Initialize the return buffer */
usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb);
@@ -1163,16 +1256,16 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->generic.TransferBlockSize = 1;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
- srb->request_bufflen = 0;
+ isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Media Status not supported, just report okay\n");
+ usb_stor_dbg(us, " Media Status not supported, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
case TEST_UNIT_READY:
- US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_TEST_UNIT_READY\n");
if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
{
@@ -1181,9 +1274,9 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->generic.TransferBlockSize = 1;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
- srb->request_bufflen = 0;
+ isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Media Status not supported, just report okay\n");
+ usb_stor_dbg(us, " Media Status not supported, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
@@ -1194,15 +1287,14 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
unsigned long capacity;
struct read_capacity_data readCapacityData;
- US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_READ_CAPACITY\n");
+
+ if (ata_id_has_lba(id))
+ capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1;
+ else
+ capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] *
+ id[ATA_ID_SECTORS]) - 1;
- if (id->capability & CAPABILITY_LBA ) {
- capacity = id->lba_capacity - 1;
- } else {
- capacity = (id->heads *
- id->cyls *
- id->sectors) - 1;
- }
readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
readCapacityData.BytesPerBlock = cpu_to_be32(0x200);
@@ -1214,21 +1306,21 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case READ_10:
- US_DEBUGP(" ATA OUT - SCSIOP_READ\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_READ\n");
lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
- if (id->capability & CAPABILITY_LBA) {
+ if (ata_id_has_lba(id)) {
sectnum = (unsigned char)(lba);
cylinder = (unsigned short)(lba>>8);
head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
} else {
- sectnum = (unsigned char)((lba % id->sectors) + 1);
- cylinder = (unsigned short)(lba / (id->sectors *
- id->heads));
- head = (unsigned char)((lba / id->sectors) %
- id->heads);
+ sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+ cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+ id[ATA_ID_HEADS]));
+ head = (u8)((lba / id[ATA_ID_SECTORS]) %
+ id[ATA_ID_HEADS]);
}
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -1242,23 +1334,25 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
- ataCdb->write.CommandByte = WIN_READ;
+ ataCdb->write.CommandByte = ATA_CMD_PIO_READ;
break;
case WRITE_10:
- US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_WRITE\n");
lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
- if (id->capability & CAPABILITY_LBA) {
+ if (ata_id_has_lba(id)) {
sectnum = (unsigned char)(lba);
cylinder = (unsigned short)(lba>>8);
head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
} else {
- sectnum = (unsigned char)((lba % id->sectors) + 1);
- cylinder = (unsigned short)(lba / (id->sectors * id->heads));
- head = (unsigned char)((lba / id->sectors) % id->heads);
+ sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1);
+ cylinder = (u16)(lba / (id[ATA_ID_SECTORS] *
+ id[ATA_ID_HEADS]));
+ head = (u8)((lba / id[ATA_ID_SECTORS]) %
+ id[ATA_ID_HEADS]);
}
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -1272,57 +1366,59 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
- ataCdb->write.CommandByte = WIN_WRITE;
+ ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE;
break;
case ALLOW_MEDIUM_REMOVAL:
- US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
- US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+ usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n",
+ srb->cmnd[4]);
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
- WIN_DOORLOCK : WIN_DOORUNLOCK;
- srb->request_bufflen = 0;
+ ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
+ isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Not removeable media, just report okay\n");
+ usb_stor_dbg(us, " Not removeable media, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
case START_STOP:
- US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n");
- US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_START_STOP_UNIT\n");
+ usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
if ((srb->cmnd[4] & 0x3) == 0x2) {
- US_DEBUGP(" Media Eject\n");
+ usb_stor_dbg(us, " Media Eject\n");
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 0;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
} else if ((srb->cmnd[4] & 0x3) == 0x1) {
- US_DEBUGP(" Get Media Status\n");
+ usb_stor_dbg(us, " Get Media Status\n");
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
- srb->request_bufflen = 0;
+ isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Nothing to do, just report okay\n");
+ usb_stor_dbg(us, " Nothing to do, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
default:
- US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]);
+ usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n",
+ srb->cmnd[0]);
srb->result = DID_ERROR << 16;
sendToTransport = 0;
break;
@@ -1344,6 +1440,7 @@ static void isd200_free_info_ptrs(void *info_)
if (info) {
kfree(info->id);
kfree(info->RegsBuf);
+ kfree(info->srb.sense_buffer);
}
}
@@ -1360,52 +1457,48 @@ static int isd200_init_info(struct us_data *us)
int retStatus = ISD200_GOOD;
struct isd200_info *info;
- info = (struct isd200_info *)
- kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct isd200_info), GFP_KERNEL);
if (!info)
retStatus = ISD200_ERROR;
else {
- memset(info, 0, sizeof(struct isd200_info));
- info->id = (struct hd_driveid *)
- kmalloc(sizeof(struct hd_driveid), GFP_KERNEL);
- info->RegsBuf = (unsigned char *)
- kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
- if (!info->id || !info->RegsBuf) {
+ info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
+ info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+ info->srb.sense_buffer =
+ kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+ if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) {
isd200_free_info_ptrs(info);
kfree(info);
retStatus = ISD200_ERROR;
- } else
- memset(info->id, 0, sizeof(struct hd_driveid));
+ }
}
if (retStatus == ISD200_GOOD) {
us->extra = info;
us->extra_destructor = isd200_free_info_ptrs;
- } else
- US_DEBUGP("ERROR - kmalloc failure\n");
+ }
- return(retStatus);
+ return retStatus;
}
/**************************************************************************
* Initialization for the ISD200
*/
-int isd200_Initialization(struct us_data *us)
+static int isd200_Initialization(struct us_data *us)
{
- US_DEBUGP("ISD200 Initialization...\n");
+ usb_stor_dbg(us, "ISD200 Initialization...\n");
/* Initialize ISD200 info struct */
if (isd200_init_info(us) == ISD200_ERROR) {
- US_DEBUGP("ERROR Initializing ISD200 Info struct\n");
+ usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n");
} else {
/* Get device specific data */
if (isd200_get_inquiry_data(us) != ISD200_GOOD)
- US_DEBUGP("ISD200 Initialization Failure\n");
+ usb_stor_dbg(us, "ISD200 Initialization Failure\n");
else
- US_DEBUGP("ISD200 Initialization complete\n");
+ usb_stor_dbg(us, "ISD200 Initialization complete\n");
}
return 0;
@@ -1416,27 +1509,64 @@ int isd200_Initialization(struct us_data *us)
* Protocol and Transport for the ISD200 ASIC
*
* This protocol and transport are for ATA devices connected to an ISD200
- * ASIC. An ATAPI device that is conected as a slave device will be
+ * ASIC. An ATAPI device that is connected as a slave device will be
* detected in the driver initialization function and the protocol will
* be changed to an ATAPI protocol (Transparent SCSI).
*
*/
-void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
{
- int sendToTransport = 1;
+ int sendToTransport = 1, orig_bufflen;
union ata_cdb ataCdb;
/* Make sure driver was initialized */
if (us->extra == NULL)
- US_DEBUGP("ERROR Driver not initialized\n");
+ usb_stor_dbg(us, "ERROR Driver not initialized\n");
- /* Convert command */
- srb->resid = 0;
+ scsi_set_resid(srb, 0);
+ /* scsi_bufflen might change in protocol translation to ata */
+ orig_bufflen = scsi_bufflen(srb);
sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
/* send the command to the transport layer */
if (sendToTransport)
isd200_invoke_transport(us, srb, &ataCdb);
+
+ isd200_srb_set_bufflen(srb, orig_bufflen);
}
+
+static int isd200_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - isd200_usb_ids) + isd200_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->protocol_name = "ISD200 ATA/ATAPI";
+ us->proto_handler = isd200_ata_command;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver isd200_driver = {
+ .name = "ums-isd200",
+ .probe = isd200_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = isd200_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(isd200_driver);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index aff9d51c327..563078be654 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -1,7 +1,5 @@
/* Driver for Lexar "Jumpshot" Compact Flash reader
*
- * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
- *
* jumpshot driver v0.1:
*
* First release
@@ -47,8 +45,8 @@
* in that routine.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
@@ -58,9 +56,61 @@
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "jumpshot.h"
+MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader");
+MODULE_AUTHOR("Jimmie Mayfield <mayfield+usb@sackheads.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id jumpshot_usb_ids[] = {
+# include "unusual_jumpshot.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, jumpshot_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev jumpshot_unusual_dev_list[] = {
+# include "unusual_jumpshot.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+struct jumpshot_info {
+ unsigned long sectors; /* total sector count */
+ unsigned long ssize; /* sector size in bytes */
+
+ /* the following aren't used yet */
+ unsigned char sense_key;
+ unsigned long sense_asc; /* additional sense code */
+ unsigned long sense_ascq; /* additional sense code qualifier */
+};
+
static inline int jumpshot_bulk_read(struct us_data *us,
unsigned char *data,
unsigned int len)
@@ -68,7 +118,7 @@ static inline int jumpshot_bulk_read(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("jumpshot_bulk_read: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
data, len, NULL);
}
@@ -81,7 +131,7 @@ static inline int jumpshot_bulk_write(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("jumpshot_bulk_write: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
data, len, NULL);
}
@@ -102,8 +152,7 @@ static int jumpshot_get_status(struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
if (us->iobuf[0] != 0x50) {
- US_DEBUGP("jumpshot_get_status: 0x%2x\n",
- us->iobuf[0]);
+ usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -120,7 +169,8 @@ static int jumpshot_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Jumpshot
@@ -167,11 +217,11 @@ static int jumpshot_read_data(struct us_data *us,
if (result != USB_STOR_XFER_GOOD)
goto leave;
- US_DEBUGP("jumpshot_read_data: %d bytes\n", len);
+ usb_stor_dbg(us, "%d bytes\n", len);
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -196,7 +246,8 @@ static int jumpshot_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result, waitcount;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Jumpshot
@@ -226,7 +277,7 @@ static int jumpshot_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
command[0] = 0;
command[1] = thistime;
@@ -262,7 +313,7 @@ static int jumpshot_write_data(struct us_data *us,
} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
if (result != USB_STOR_TRANSPORT_GOOD)
- US_DEBUGP("jumpshot_write_data: Gah! Waitcount = 10. Bad write!?\n");
+ usb_stor_dbg(us, "Gah! Waitcount = 10. Bad write!?\n");
sector += thistime;
totallen -= len;
@@ -283,7 +334,7 @@ static int jumpshot_id_device(struct us_data *us,
unsigned char *reply;
int rc;
- if (!us || !info)
+ if (!info)
return USB_STOR_TRANSPORT_ERROR;
command[0] = 0xE0;
@@ -297,8 +348,7 @@ static int jumpshot_id_device(struct us_data *us,
0, 0x20, 0, 6, command, 2);
if (rc != USB_STOR_XFER_GOOD) {
- US_DEBUGP("jumpshot_id_device: Gah! "
- "send_control for read_capacity failed\n");
+ usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n");
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -348,17 +398,17 @@ static int jumpshot_handle_mode_sense(struct us_data *us,
switch (pc) {
case 0x0:
- US_DEBUGP("jumpshot_handle_mode_sense: Current values\n");
- break;
+ usb_stor_dbg(us, "Current values\n");
+ break;
case 0x1:
- US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n");
- break;
+ usb_stor_dbg(us, "Changeable values\n");
+ break;
case 0x2:
- US_DEBUGP("jumpshot_handle_mode_sense: Default values\n");
- break;
+ usb_stor_dbg(us, "Default values\n");
+ break;
case 0x3:
- US_DEBUGP("jumpshot_handle_mode_sense: Saves values\n");
- break;
+ usb_stor_dbg(us, "Saves values\n");
+ break;
}
memset(ptr, 0, 8);
@@ -430,7 +480,7 @@ static void jumpshot_info_destructor(void *extra)
// Transport for the Lexar 'Jumpshot'
//
-int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
+static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct jumpshot_info *info;
int rc;
@@ -441,19 +491,17 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
};
if (!us->extra) {
- us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n");
+ us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+ if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- }
- memset(us->extra, 0, sizeof(struct jumpshot_info));
+
us->extra_destructor = jumpshot_info_destructor;
}
info = (struct jumpshot_info *) (us->extra);
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_response, sizeof(inquiry_response));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -470,8 +518,8 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("jumpshot_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
// build the reply
//
@@ -483,7 +531,7 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("jumpshot_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -493,7 +541,8 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("jumpshot_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_read_data(us, info, block, blocks);
}
@@ -506,7 +555,8 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("jumpshot_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_read_data(us, info, block, blocks);
}
@@ -516,7 +566,8 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("jumpshot_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_write_data(us, info, block, blocks);
}
@@ -529,18 +580,19 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
return jumpshot_get_status(us);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("jumpshot_transport: REQUEST_SENSE.\n");
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
memset(ptr, 0, 18);
ptr[0] = 0xF0;
@@ -554,12 +606,12 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SENSE) {
- US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
return jumpshot_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
- US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
return jumpshot_handle_mode_sense(us, srb, 0);
}
@@ -573,7 +625,7 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
if (srb->cmnd[0] == START_STOP) {
/* this is used by sd.c'check_scsidisk_media_change to detect
media change */
- US_DEBUGP("jumpshot_transport: START_STOP.\n");
+ usb_stor_dbg(us, "START_STOP\n");
/* the first jumpshot_id_device after a media change returns
an error (determined experimentally) */
rc = jumpshot_id_device(us, info);
@@ -587,10 +639,46 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
return rc;
}
- US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
return USB_STOR_TRANSPORT_FAILED;
}
+
+static int jumpshot_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - jumpshot_usb_ids) + jumpshot_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "Lexar Jumpshot Control/Bulk";
+ us->transport = jumpshot_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ us->max_lun = 1;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver jumpshot_driver = {
+ .name = "ums-jumpshot",
+ .probe = jumpshot_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = jumpshot_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(jumpshot_driver);
diff --git a/drivers/usb/storage/jumpshot.h b/drivers/usb/storage/jumpshot.h
deleted file mode 100644
index 19bac9d1558..00000000000
--- a/drivers/usb/storage/jumpshot.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Driver for Lexar "Jumpshot" USB Compact Flash reader
- * Header File
- *
- * Current development and maintenance by:
- * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
- *
- * See jumpshot.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _USB_JUMPSHOT_H
-#define _USB_JUMPSHOT_H
-
-extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us);
-
-struct jumpshot_info {
- unsigned long sectors; // total sector count
- unsigned long ssize; // sector size in bytes
-
- // the following aren't used yet
- unsigned char sense_key;
- unsigned long sense_asc; // additional sense code
- unsigned long sense_ascq; // additional sense code qualifier
-};
-
-#endif
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
new file mode 100644
index 00000000000..94d16ee5e84
--- /dev/null
+++ b/drivers/usb/storage/karma.c
@@ -0,0 +1,236 @@
+/* Driver for Rio Karma
+ *
+ * (c) 2006 Bob Copeland <me@bobcopeland.com>
+ * (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "debug.h"
+
+MODULE_DESCRIPTION("Driver for Rio Karma");
+MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>, Keith Bennett <keith@mcs.st-and.ac.uk>");
+MODULE_LICENSE("GPL");
+
+#define RIO_PREFIX "RIOP\x00"
+#define RIO_PREFIX_LEN 5
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
+#define RIO_ENTER_STORAGE 0x1
+#define RIO_LEAVE_STORAGE 0x2
+#define RIO_RESET 0xC
+
+struct karma_data {
+ int in_storage;
+ char *recv;
+};
+
+static int rio_karma_init(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id karma_usb_ids[] = {
+# include "unusual_karma.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, karma_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev karma_unusual_dev_list[] = {
+# include "unusual_karma.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+
+/*
+ * Send commands to Rio Karma.
+ *
+ * For each command we send 40 bytes starting 'RIOP\0' followed by
+ * the command number and a sequence number, which the device will ack
+ * with a 512-byte packet with the high four bits set and everything
+ * else null. Then we send 'RIOP\x80' followed by a zero and the
+ * sequence number, until byte 5 in the response repeats the sequence
+ * number.
+ */
+static int rio_karma_send_command(char cmd, struct us_data *us)
+{
+ int result, partial;
+ unsigned long timeout;
+ static unsigned char seq = 1;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ usb_stor_dbg(us, "sending command %04x\n", cmd);
+ memset(us->iobuf, 0, RIO_SEND_LEN);
+ memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
+ us->iobuf[5] = cmd;
+ us->iobuf[6] = seq;
+
+ timeout = jiffies + msecs_to_jiffies(6000);
+ for (;;) {
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ us->iobuf, RIO_SEND_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data->recv, RIO_RECV_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ if (data->recv[5] == seq)
+ break;
+
+ if (time_after(jiffies, timeout))
+ goto err;
+
+ us->iobuf[4] = 0x80;
+ us->iobuf[5] = 0;
+ msleep(50);
+ }
+
+ seq++;
+ if (seq == 0)
+ seq = 1;
+
+ usb_stor_dbg(us, "sent command %04x\n", cmd);
+ return 0;
+err:
+ usb_stor_dbg(us, "command %04x failed\n", cmd);
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Trap START_STOP and READ_10 to leave/re-enter storage mode.
+ * Everything else is propagated to the normal bulk layer.
+ */
+static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int ret;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ if (srb->cmnd[0] == READ_10 && !data->in_storage) {
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 1;
+ return usb_stor_Bulk_transport(srb, us);
+ } else if (srb->cmnd[0] == START_STOP) {
+ ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 0;
+ return rio_karma_send_command(RIO_RESET, us);
+ }
+ return usb_stor_Bulk_transport(srb, us);
+}
+
+static void rio_karma_destructor(void *extra)
+{
+ struct karma_data *data = (struct karma_data *) extra;
+ kfree(data->recv);
+}
+
+static int rio_karma_init(struct us_data *us)
+{
+ int ret = 0;
+ struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
+ if (!data)
+ goto out;
+
+ data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
+ if (!data->recv) {
+ kfree(data);
+ goto out;
+ }
+
+ us->extra = data;
+ us->extra_destructor = rio_karma_destructor;
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ data->in_storage = (ret == 0);
+out:
+ return ret;
+}
+
+static int karma_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - karma_usb_ids) + karma_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "Rio Karma/Bulk";
+ us->transport = rio_karma_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver karma_driver = {
+ .name = "ums-karma",
+ .probe = karma_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = karma_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(karma_driver);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 89401a59f95..74e2aa23b04 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -28,20 +28,23 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/input.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb_ch9.h>
-#include <linux/usb_input.h>
+#include <linux/usb/input.h>
#include "usb.h"
-#include "onetouch.h"
#include "debug.h"
-void onetouch_release_input(void *onetouch_);
+MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
+MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
+MODULE_LICENSE("GPL");
+
+#define ONETOUCH_PKT_LEN 0x02
+#define ONETOUCH_BUTTON KEY_PROG1
+
+static int onetouch_connect_input(struct us_data *ss);
+static void onetouch_release_input(void *onetouch_);
struct usb_onetouch {
char name[128];
@@ -52,16 +55,58 @@ struct usb_onetouch {
struct urb *irq; /* urb for interrupt in report */
unsigned char *data; /* input data */
dma_addr_t data_dma;
+ unsigned int is_open:1;
+};
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id onetouch_usb_ids[] = {
+# include "unusual_onetouch.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, onetouch_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev onetouch_unusual_dev_list[] = {
+# include "unusual_onetouch.h"
+ { } /* Terminating entry */
};
-static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
+#undef UNUSUAL_DEV
+
+
+static void usb_onetouch_irq(struct urb *urb)
{
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
struct input_dev *dev = onetouch->dev;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -73,25 +118,25 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
- input_regs(dev, regs);
input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
input_sync(dev);
resubmit:
- status = usb_submit_urb (urb, SLAB_ATOMIC);
- if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- onetouch->udev->bus->bus_name,
- onetouch->udev->devpath, status);
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
+ "retval %d\n", onetouch->udev->bus->bus_name,
+ onetouch->udev->devpath, retval);
}
static int usb_onetouch_open(struct input_dev *dev)
{
- struct usb_onetouch *onetouch = dev->private;
+ struct usb_onetouch *onetouch = input_get_drvdata(dev);
+ onetouch->is_open = 1;
onetouch->irq->dev = onetouch->udev;
if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
- err("usb_submit_urb failed");
+ dev_err(&dev->dev, "usb_submit_urb failed\n");
return -EIO;
}
@@ -100,12 +145,35 @@ static int usb_onetouch_open(struct input_dev *dev)
static void usb_onetouch_close(struct input_dev *dev)
{
- struct usb_onetouch *onetouch = dev->private;
+ struct usb_onetouch *onetouch = input_get_drvdata(dev);
usb_kill_urb(onetouch->irq);
+ onetouch->is_open = 0;
}
-int onetouch_connect_input(struct us_data *ss)
+#ifdef CONFIG_PM
+static void usb_onetouch_pm_hook(struct us_data *us, int action)
+{
+ struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
+
+ if (onetouch->is_open) {
+ switch (action) {
+ case US_SUSPEND:
+ usb_kill_urb(onetouch->irq);
+ break;
+ case US_RESUME:
+ if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
+ dev_err(&onetouch->irq->dev->dev,
+ "usb_submit_urb failed\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+#endif /* CONFIG_PM */
+
+static int onetouch_connect_input(struct us_data *ss)
{
struct usb_device *udev = ss->pusb_dev;
struct usb_host_interface *interface;
@@ -113,6 +181,7 @@ int onetouch_connect_input(struct us_data *ss)
struct usb_onetouch *onetouch;
struct input_dev *input_dev;
int pipe, maxp;
+ int error = -ENOMEM;
interface = ss->pusb_intf->cur_altsetting;
@@ -120,22 +189,20 @@ int onetouch_connect_input(struct us_data *ss)
return -ENODEV;
endpoint = &interface->endpoint[2].desc;
- if (!(endpoint->bEndpointAddress & USB_DIR_IN))
- return -ENODEV;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ maxp = min(maxp, ONETOUCH_PKT_LEN);
onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!onetouch || !input_dev)
goto fail1;
- onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
- SLAB_ATOMIC, &onetouch->data_dma);
+ onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
+ GFP_KERNEL, &onetouch->data_dma);
if (!onetouch->data)
goto fail1;
@@ -167,37 +234,43 @@ int onetouch_connect_input(struct us_data *ss)
input_dev->name = onetouch->name;
input_dev->phys = onetouch->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &udev->dev;
+ input_dev->dev.parent = &udev->dev;
set_bit(EV_KEY, input_dev->evbit);
set_bit(ONETOUCH_BUTTON, input_dev->keybit);
clear_bit(0, input_dev->keybit);
- input_dev->private = onetouch;
+ input_set_drvdata(input_dev, onetouch);
+
input_dev->open = usb_onetouch_open;
input_dev->close = usb_onetouch_close;
- usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
- (maxp > 8 ? 8 : maxp),
+ usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
usb_onetouch_irq, onetouch, endpoint->bInterval);
onetouch->irq->transfer_dma = onetouch->data_dma;
onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
ss->extra_destructor = onetouch_release_input;
ss->extra = onetouch;
+#ifdef CONFIG_PM
+ ss->suspend_resume_hook = usb_onetouch_pm_hook;
+#endif
- input_register_device(onetouch->dev);
+ error = input_register_device(onetouch->dev);
+ if (error)
+ goto fail3;
return 0;
- fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN,
- onetouch->data, onetouch->data_dma);
+ fail3: usb_free_urb(onetouch->irq);
+ fail2: usb_free_coherent(udev, ONETOUCH_PKT_LEN,
+ onetouch->data, onetouch->data_dma);
fail1: kfree(onetouch);
input_free_device(input_dev);
- return -ENOMEM;
+ return error;
}
-void onetouch_release_input(void *onetouch_)
+static void onetouch_release_input(void *onetouch_)
{
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
@@ -205,7 +278,40 @@ void onetouch_release_input(void *onetouch_)
usb_kill_urb(onetouch->irq);
input_unregister_device(onetouch->dev);
usb_free_urb(onetouch->irq);
- usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN,
- onetouch->data, onetouch->data_dma);
+ usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
+ onetouch->data, onetouch->data_dma);
}
}
+
+static int onetouch_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - onetouch_usb_ids) + onetouch_unusual_dev_list);
+ if (result)
+ return result;
+
+ /* Use default transport and protocol */
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver onetouch_driver = {
+ .name = "ums-onetouch",
+ .probe = onetouch_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = onetouch_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(onetouch_driver);
diff --git a/drivers/usb/storage/onetouch.h b/drivers/usb/storage/onetouch.h
deleted file mode 100644
index 41c7aa8f044..00000000000
--- a/drivers/usb/storage/onetouch.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _ONETOUCH_H_
-#define _ONETOUCH_H_
-
-#define ONETOUCH_PKT_LEN 0x02
-#define ONETOUCH_BUTTON KEY_PROG1
-
-int onetouch_connect_input(struct us_data *ss);
-
-#endif
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
new file mode 100644
index 00000000000..b2b35b1d7de
--- /dev/null
+++ b/drivers/usb/storage/option_ms.c
@@ -0,0 +1,171 @@
+/*
+ * Driver for Option High Speed Mobile Devices.
+ *
+ * (c) 2008 Dan Williams <dcbw@redhat.com>
+ *
+ * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "option_ms.h"
+#include "debug.h"
+
+#define ZCD_FORCE_MODEM 0x01
+#define ZCD_ALLOW_MS 0x02
+
+static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
+module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
+ " 2=Allow CD-Rom");
+
+#define RESPONSE_LEN 1024
+
+static int option_rezero(struct us_data *us)
+{
+ const unsigned char rezero_msg[] = {
+ 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
+ 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ char *buffer;
+ int result;
+
+ usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
+
+ buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memcpy(buffer, rezero_msg, sizeof(rezero_msg));
+ result = usb_stor_bulk_transfer_buf(us,
+ us->send_bulk_pipe,
+ buffer, sizeof(rezero_msg), NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_XFER_ERROR;
+ goto out;
+ }
+
+ /* Some of the devices need to be asked for a response, but we don't
+ * care what that response is.
+ */
+ usb_stor_bulk_transfer_buf(us,
+ us->recv_bulk_pipe,
+ buffer, RESPONSE_LEN, NULL);
+
+ /* Read the CSW */
+ usb_stor_bulk_transfer_buf(us,
+ us->recv_bulk_pipe,
+ buffer, 13, NULL);
+
+ result = USB_STOR_XFER_GOOD;
+
+out:
+ kfree(buffer);
+ return result;
+}
+
+static int option_inquiry(struct us_data *us)
+{
+ const unsigned char inquiry_msg[] = {
+ 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
+ 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
+ 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ char *buffer;
+ int result;
+
+ usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
+
+ buffer = kzalloc(0x24, GFP_KERNEL);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
+ result = usb_stor_bulk_transfer_buf(us,
+ us->send_bulk_pipe,
+ buffer, sizeof(inquiry_msg), NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_XFER_ERROR;
+ goto out;
+ }
+
+ result = usb_stor_bulk_transfer_buf(us,
+ us->recv_bulk_pipe,
+ buffer, 0x24, NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_XFER_ERROR;
+ goto out;
+ }
+
+ result = memcmp(buffer+8, "Option", 6);
+
+ if (result != 0)
+ result = memcmp(buffer+8, "ZCOPTION", 8);
+
+ /* Read the CSW */
+ usb_stor_bulk_transfer_buf(us,
+ us->recv_bulk_pipe,
+ buffer, 13, NULL);
+
+out:
+ kfree(buffer);
+ return result;
+}
+
+
+int option_ms_init(struct us_data *us)
+{
+ int result;
+
+ usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
+
+ /* Additional test for vendor information via INQUIRY,
+ * because some vendor/product IDs are ambiguous
+ */
+ result = option_inquiry(us);
+ if (result != 0) {
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "vendor is not Option or not determinable, no action taken");
+ return 0;
+ } else
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "this is a genuine Option device, proceeding");
+
+ /* Force Modem mode */
+ if (option_zero_cd == ZCD_FORCE_MODEM) {
+ usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
+ result = option_rezero(us);
+ if (result != USB_STOR_XFER_GOOD)
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "Failed to switch to modem mode");
+ return -EIO;
+ } else if (option_zero_cd == ZCD_ALLOW_MS) {
+ /* Allow Mass Storage mode (keep CD-Rom) */
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "Allowing Mass Storage Mode if device requests it");
+ }
+
+ return 0;
+}
+
diff --git a/drivers/usb/storage/option_ms.h b/drivers/usb/storage/option_ms.h
new file mode 100644
index 00000000000..b6e448cab03
--- /dev/null
+++ b/drivers/usb/storage/option_ms.h
@@ -0,0 +1,4 @@
+#ifndef _OPTION_MS_H_
+#define _OPTION_MS_H_
+extern int option_ms_init(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 9ad30428d2d..12e3c2fac64 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -1,7 +1,5 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: protocol.c,v 1.14 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -45,6 +43,7 @@
*/
#include <linux/highmem.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -58,54 +57,33 @@
* Protocol routines
***********************************************************************/
-void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
+void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
{
- /* Pad the ATAPI command with zeros
+ /*
+ * Pad the SCSI command with zeros out to 12 bytes. If the
+ * command already is 12 bytes or longer, leave it alone.
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
- for (; srb->cmd_len<12; srb->cmd_len++)
+ for (; srb->cmd_len < 12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
- /* set command length to 12 bytes */
- srb->cmd_len = 12;
-
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
-void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
-{
- /* Pad the ATAPI command with zeros
- *
- * NOTE: This only works because a scsi_cmnd struct field contains
- * a unsigned char cmnd[16], so we know we have storage available
- */
-
- /* Pad the ATAPI command with zeros */
- for (; srb->cmd_len<12; srb->cmd_len++)
- srb->cmnd[srb->cmd_len] = 0;
-
- /* set command length to 12 bytes */
- srb->cmd_len = 12;
-
- /* send the command to the transport layer */
- usb_stor_invoke_transport(srb, us);
-}
-
-
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* fix some commands -- this is a form of mode translation
- * UFI devices only accept 12 byte long commands
+ * UFI devices only accept 12 byte long commands
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
/* Pad the ATAPI command with zeros */
- for (; srb->cmd_len<12; srb->cmd_len++)
+ for (; srb->cmd_len < 12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
/* set command length to 12 bytes (this affects the transport layer) */
@@ -143,112 +121,73 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
+EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command);
/***********************************************************************
* Scatter-gather transfer buffer access routines
***********************************************************************/
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
- * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
- * points to a list of s-g entries and we ignore srb->request_bufflen.
- * For non-scatter-gather transfers, srb->request_buffer points to the
- * transfer buffer itself and srb->request_bufflen is the buffer's length.)
- * Update the *index and *offset variables so that the next copy will
- * pick up from where this one left off. */
-
+ * Update the **sgptr and *offset variables so that the next copy will
+ * pick up from where this one left off.
+ */
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+ unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
{
- unsigned int cnt;
-
- /* If not using scatter-gather, just transfer the data directly.
- * Make certain it will fit in the available buffer space. */
- if (srb->use_sg == 0) {
- if (*offset >= srb->request_bufflen)
- return 0;
- cnt = min(buflen, srb->request_bufflen - *offset);
- if (dir == TO_XFER_BUF)
- memcpy((unsigned char *) srb->request_buffer + *offset,
- buffer, cnt);
+ unsigned int cnt = 0;
+ struct scatterlist *sg = *sgptr;
+ struct sg_mapping_iter miter;
+ unsigned int nents = scsi_sg_count(srb);
+
+ if (sg)
+ nents = sg_nents(sg);
+ else
+ sg = scsi_sglist(srb);
+
+ sg_miter_start(&miter, sg, nents, dir == FROM_XFER_BUF ?
+ SG_MITER_FROM_SG: SG_MITER_TO_SG);
+
+ if (!sg_miter_skip(&miter, *offset))
+ return cnt;
+
+ while (sg_miter_next(&miter) && cnt < buflen) {
+ unsigned int len = min_t(unsigned int, miter.length,
+ buflen - cnt);
+
+ if (dir == FROM_XFER_BUF)
+ memcpy(buffer + cnt, miter.addr, len);
else
- memcpy(buffer, (unsigned char *) srb->request_buffer +
- *offset, cnt);
- *offset += cnt;
-
- /* Using scatter-gather. We have to go through the list one entry
- * at a time. Each s-g entry contains some number of pages, and
- * each page has to be kmap()'ed separately. If the page is already
- * in kernel-addressable memory then kmap() will return its address.
- * If the page is not directly accessible -- such as a user buffer
- * located in high memory -- then kmap() will map it to a temporary
- * position in the kernel's virtual address space. */
- } else {
- struct scatterlist *sg =
- (struct scatterlist *) srb->request_buffer
- + *index;
-
- /* This loop handles a single s-g list entry, which may
- * include multiple pages. Find the initial page structure
- * and the starting offset within the page, and update
- * the *offset and *index values for the next loop. */
- cnt = 0;
- while (cnt < buflen && *index < srb->use_sg) {
- struct page *page = sg->page +
- ((sg->offset + *offset) >> PAGE_SHIFT);
- unsigned int poff =
- (sg->offset + *offset) & (PAGE_SIZE-1);
- unsigned int sglen = sg->length - *offset;
-
- if (sglen > buflen - cnt) {
-
- /* Transfer ends within this s-g entry */
- sglen = buflen - cnt;
- *offset += sglen;
- } else {
-
- /* Transfer continues to next s-g entry */
- *offset = 0;
- ++*index;
- ++sg;
- }
-
- /* Transfer the data for all the pages in this
- * s-g entry. For each page: call kmap(), do the
- * transfer, and call kunmap() immediately after. */
- while (sglen > 0) {
- unsigned int plen = min(sglen, (unsigned int)
- PAGE_SIZE - poff);
- unsigned char *ptr = kmap(page);
-
- if (dir == TO_XFER_BUF)
- memcpy(ptr + poff, buffer + cnt, plen);
- else
- memcpy(buffer + cnt, ptr + poff, plen);
- kunmap(page);
-
- /* Start at the beginning of the next page */
- poff = 0;
- ++page;
- cnt += plen;
- sglen -= plen;
- }
+ memcpy(miter.addr, buffer + cnt, len);
+
+ if (*offset + len < miter.piter.sg->length) {
+ *offset += len;
+ *sgptr = miter.piter.sg;
+ } else {
+ *offset = 0;
+ *sgptr = sg_next(miter.piter.sg);
}
+ cnt += len;
}
+ sg_miter_stop(&miter);
- /* Return the amount actually transferred */
return cnt;
}
+EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf);
/* Store the contents of buffer into srb's transfer buffer and set the
- * SCSI residue. */
+ * SCSI residue.
+ */
void usb_stor_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
- unsigned int index = 0, offset = 0;
+ unsigned int offset = 0;
+ struct scatterlist *sg = NULL;
- usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
+ buflen = min(buflen, scsi_bufflen(srb));
+ buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
TO_XFER_BUF);
- if (buflen < srb->request_bufflen)
- srb->resid = srb->request_bufflen - buflen;
+ if (buflen < scsi_bufflen(srb))
+ scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
+EXPORT_SYMBOL_GPL(usb_stor_set_xfer_buf);
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 02bff01ab09..ffc3e2af015 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Protocol Functions Header File
*
- * $Id: protocol.h,v 1.4 2001/02/13 07:10:03 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -41,23 +39,8 @@
#ifndef _PROTOCOL_H_
#define _PROTOCOL_H_
-/* 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_ISD200 0x07 /* ISD200 ATA */
-#define US_SC_MIN US_SC_RBC
-#define US_SC_MAX US_SC_ISD200
-
-#define US_SC_DEVICE 0xff /* Use device's value */
-
/* Protocol handling routines */
-extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*);
-extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_pad12_command(struct scsi_cmnd*, struct us_data*);
extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
struct us_data*);
@@ -66,7 +49,7 @@ extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+ unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **,
unsigned int *offset, enum xfer_buf_dir dir);
extern void usb_stor_set_xfer_buf(unsigned char *buffer,
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
new file mode 100644
index 00000000000..281be56d564
--- /dev/null
+++ b/drivers/usb/storage/realtek_cr.c
@@ -0,0 +1,1071 @@
+/* Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <linux/cdrom.h>
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/usb_usual.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+
+MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
+MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.03");
+
+static int auto_delink_en = 1;
+module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
+
+#ifdef CONFIG_REALTEK_AUTOPM
+static int ss_en = 1;
+module_param(ss_en, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ss_en, "enable selective suspend");
+
+static int ss_delay = 50;
+module_param(ss_delay, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ss_delay,
+ "seconds to delay before entering selective suspend");
+
+enum RTS51X_STAT {
+ RTS51X_STAT_INIT,
+ RTS51X_STAT_IDLE,
+ RTS51X_STAT_RUN,
+ RTS51X_STAT_SS
+};
+
+#define POLLING_INTERVAL 50
+
+#define rts51x_set_stat(chip, stat) \
+ ((chip)->state = (enum RTS51X_STAT)(stat))
+#define rts51x_get_stat(chip) ((chip)->state)
+
+#define SET_LUN_READY(chip, lun) ((chip)->lun_ready |= ((u8)1 << (lun)))
+#define CLR_LUN_READY(chip, lun) ((chip)->lun_ready &= ~((u8)1 << (lun)))
+#define TST_LUN_READY(chip, lun) ((chip)->lun_ready & ((u8)1 << (lun)))
+
+#endif
+
+struct rts51x_status {
+ u16 vid;
+ u16 pid;
+ u8 cur_lun;
+ u8 card_type;
+ u8 total_lun;
+ u16 fw_ver;
+ u8 phy_exist;
+ u8 multi_flag;
+ u8 multi_card;
+ u8 log_exist;
+ union {
+ u8 detailed_type1;
+ u8 detailed_type2;
+ } detailed_type;
+ u8 function[2];
+};
+
+struct rts51x_chip {
+ u16 vendor_id;
+ u16 product_id;
+ char max_lun;
+
+ struct rts51x_status *status;
+ int status_len;
+
+ u32 flag;
+ struct us_data *us;
+
+#ifdef CONFIG_REALTEK_AUTOPM
+ struct timer_list rts51x_suspend_timer;
+ unsigned long timer_expires;
+ int pwr_state;
+ u8 lun_ready;
+ enum RTS51X_STAT state;
+ int support_auto_delink;
+#endif
+ /* used to back up the protocal choosen in probe1 phase */
+ proto_cmnd proto_handler_backup;
+};
+
+/* flag definition */
+#define FLIDX_AUTO_DELINK 0x01
+
+#define SCSI_LUN(srb) ((srb)->device->lun)
+
+/* Bit Operation */
+#define SET_BIT(data, idx) ((data) |= 1 << (idx))
+#define CLR_BIT(data, idx) ((data) &= ~(1 << (idx)))
+#define CHK_BIT(data, idx) ((data) & (1 << (idx)))
+
+#define SET_AUTO_DELINK(chip) ((chip)->flag |= FLIDX_AUTO_DELINK)
+#define CLR_AUTO_DELINK(chip) ((chip)->flag &= ~FLIDX_AUTO_DELINK)
+#define CHK_AUTO_DELINK(chip) ((chip)->flag & FLIDX_AUTO_DELINK)
+
+#define RTS51X_GET_VID(chip) ((chip)->vendor_id)
+#define RTS51X_GET_PID(chip) ((chip)->product_id)
+
+#define VENDOR_ID(chip) ((chip)->status[0].vid)
+#define PRODUCT_ID(chip) ((chip)->status[0].pid)
+#define FW_VERSION(chip) ((chip)->status[0].fw_ver)
+#define STATUS_LEN(chip) ((chip)->status_len)
+
+#define STATUS_SUCCESS 0
+#define STATUS_FAIL 1
+
+/* Check card reader function */
+#define SUPPORT_DETAILED_TYPE1(chip) \
+ CHK_BIT((chip)->status[0].function[0], 1)
+#define SUPPORT_OT(chip) \
+ CHK_BIT((chip)->status[0].function[0], 2)
+#define SUPPORT_OC(chip) \
+ CHK_BIT((chip)->status[0].function[0], 3)
+#define SUPPORT_AUTO_DELINK(chip) \
+ CHK_BIT((chip)->status[0].function[0], 4)
+#define SUPPORT_SDIO(chip) \
+ CHK_BIT((chip)->status[0].function[1], 0)
+#define SUPPORT_DETAILED_TYPE2(chip) \
+ CHK_BIT((chip)->status[0].function[1], 1)
+
+#define CHECK_PID(chip, pid) (RTS51X_GET_PID(chip) == (pid))
+#define CHECK_FW_VER(chip, fw_ver) (FW_VERSION(chip) == (fw_ver))
+#define CHECK_ID(chip, pid, fw_ver) \
+ (CHECK_PID((chip), (pid)) && CHECK_FW_VER((chip), (fw_ver)))
+
+static int init_realtek_cr(struct us_data *us);
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{\
+ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) \
+}
+
+static const struct usb_device_id realtek_cr_ids[] = {
+# include "unusual_realtek.h"
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, realtek_cr_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev realtek_cr_unusual_dev_list[] = {
+# include "unusual_realtek.h"
+ {} /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+static int rts51x_bulk_transport(struct us_data *us, u8 lun,
+ u8 *cmd, int cmd_len, u8 *buf, int buf_len,
+ enum dma_data_direction dir, int *act_len)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *)us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *)us->iobuf;
+ int result;
+ unsigned int residue;
+ unsigned int cswlen;
+ unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+ /* set up the command wrapper */
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = cpu_to_le32(buf_len);
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+ bcb->Tag = ++us->tag;
+ bcb->Lun = lun;
+ bcb->Length = cmd_len;
+
+ /* copy the command payload */
+ memset(bcb->CDB, 0, sizeof(bcb->CDB));
+ memcpy(bcb->CDB, cmd, bcb->Length);
+
+ /* send it to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, cbwlen, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* DATA STAGE */
+ /* send/receive data payload, if there is any */
+
+ if (buf && buf_len) {
+ unsigned int pipe = (dir == DMA_FROM_DEVICE) ?
+ us->recv_bulk_pipe : us->send_bulk_pipe;
+ result = usb_stor_bulk_transfer_buf(us, pipe,
+ buf, buf_len, NULL);
+ if (result == USB_STOR_XFER_ERROR)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* check bulk status */
+ if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN)) {
+ usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ residue = bcs->Residue;
+ if (bcs->Tag != us->tag)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* try to compute the actual residue, based on how much data
+ * was really transferred and what the device tells us */
+ if (residue)
+ residue = residue < buf_len ? residue : buf_len;
+
+ if (act_len)
+ *act_len = buf_len - residue;
+
+ /* based on the status code, we report good or bad */
+ switch (bcs->Status) {
+ case US_BULK_STAT_OK:
+ /* command good -- note that data could be short */
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ /* phase error -- note that a transport reset will be
+ * invoked by the invoke_transport() function
+ */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
+ u8 *cmd, int cmd_len, u8 *buf, int buf_len,
+ enum dma_data_direction dir, int *act_len)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+ int result;
+ unsigned int cswlen;
+ unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+ /* set up the command wrapper */
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = cpu_to_le32(buf_len);
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
+ bcb->Tag = ++us->tag;
+ bcb->Lun = lun;
+ bcb->Length = cmd_len;
+
+ /* copy the command payload */
+ memset(bcb->CDB, 0, sizeof(bcb->CDB));
+ memcpy(bcb->CDB, cmd, bcb->Length);
+
+ /* send it to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, cbwlen, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* DATA STAGE */
+ /* send/receive data payload, if there is any */
+
+ if (buf && buf_len) {
+ unsigned int pipe = (dir == DMA_FROM_DEVICE) ?
+ us->recv_bulk_pipe : us->send_bulk_pipe;
+ result = usb_stor_bulk_transfer_buf(us, pipe,
+ buf, buf_len, NULL);
+ if (result == USB_STOR_XFER_ERROR)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* get CSW for device status */
+ result = usb_bulk_msg(us->pusb_dev, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen, 250);
+ return result;
+}
+
+/* Determine what the maximum LUN supported is */
+static int rts51x_get_max_lun(struct us_data *us)
+{
+ int result;
+
+ /* issue the command */
+ us->iobuf[0] = 0;
+ result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+ US_BULK_GET_MAX_LUN,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ 0, us->ifnum, us->iobuf, 1, 10 * HZ);
+
+ usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+ result, us->iobuf[0]);
+
+ /* if we have a successful request, return the result */
+ if (result > 0)
+ return us->iobuf[0];
+
+ return 0;
+}
+
+static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+{
+ int retval;
+ u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmalloc(len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
+
+ cmnd[0] = 0xF0;
+ cmnd[1] = 0x0D;
+ cmnd[2] = (u8) (addr >> 8);
+ cmnd[3] = (u8) addr;
+ cmnd[4] = (u8) (len >> 8);
+ cmnd[5] = (u8) len;
+
+ retval = rts51x_bulk_transport(us, 0, cmnd, 12,
+ buf, len, DMA_FROM_DEVICE, NULL);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ kfree(buf);
+ return -EIO;
+ }
+
+ memcpy(data, buf, len);
+ kfree(buf);
+ return 0;
+}
+
+static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
+{
+ int retval;
+ u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmemdup(data, len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
+
+ cmnd[0] = 0xF0;
+ cmnd[1] = 0x0E;
+ cmnd[2] = (u8) (addr >> 8);
+ cmnd[3] = (u8) addr;
+ cmnd[4] = (u8) (len >> 8);
+ cmnd[5] = (u8) len;
+
+ retval = rts51x_bulk_transport(us, 0, cmnd, 12,
+ buf, len, DMA_TO_DEVICE, NULL);
+ kfree(buf);
+ if (retval != USB_STOR_TRANSPORT_GOOD)
+ return -EIO;
+
+ return 0;
+}
+
+static int rts51x_read_status(struct us_data *us,
+ u8 lun, u8 *status, int len, int *actlen)
+{
+ int retval;
+ u8 cmnd[12] = { 0 };
+ u8 *buf;
+
+ buf = kmalloc(len, GFP_NOIO);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ usb_stor_dbg(us, "lun = %d\n", lun);
+
+ cmnd[0] = 0xF0;
+ cmnd[1] = 0x09;
+
+ retval = rts51x_bulk_transport(us, lun, cmnd, 12,
+ buf, len, DMA_FROM_DEVICE, actlen);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ kfree(buf);
+ return -EIO;
+ }
+
+ memcpy(status, buf, len);
+ kfree(buf);
+ return 0;
+}
+
+static int rts51x_check_status(struct us_data *us, u8 lun)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ int retval;
+ u8 buf[16];
+
+ retval = rts51x_read_status(us, lun, buf, 16, &(chip->status_len));
+ if (retval != STATUS_SUCCESS)
+ return -EIO;
+
+ usb_stor_dbg(us, "chip->status_len = %d\n", chip->status_len);
+
+ chip->status[lun].vid = ((u16) buf[0] << 8) | buf[1];
+ chip->status[lun].pid = ((u16) buf[2] << 8) | buf[3];
+ chip->status[lun].cur_lun = buf[4];
+ chip->status[lun].card_type = buf[5];
+ chip->status[lun].total_lun = buf[6];
+ chip->status[lun].fw_ver = ((u16) buf[7] << 8) | buf[8];
+ chip->status[lun].phy_exist = buf[9];
+ chip->status[lun].multi_flag = buf[10];
+ chip->status[lun].multi_card = buf[11];
+ chip->status[lun].log_exist = buf[12];
+ if (chip->status_len == 16) {
+ chip->status[lun].detailed_type.detailed_type1 = buf[13];
+ chip->status[lun].function[0] = buf[14];
+ chip->status[lun].function[1] = buf[15];
+ }
+
+ return 0;
+}
+
+static int enable_oscillator(struct us_data *us)
+{
+ int retval;
+ u8 value;
+
+ retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ value |= 0x04;
+ retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (!(value & 0x04))
+ return -EIO;
+
+ return 0;
+}
+
+static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
+{
+ int retval;
+ u8 cmnd[12] = {0};
+ u8 *buf;
+
+ usb_stor_dbg(us, "addr = 0xfe47, len = %d\n", len);
+
+ buf = kmemdup(data, len, GFP_NOIO);
+ if (!buf)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ cmnd[0] = 0xF0;
+ cmnd[1] = 0x0E;
+ cmnd[2] = 0xfe;
+ cmnd[3] = 0x47;
+ cmnd[4] = (u8)(len >> 8);
+ cmnd[5] = (u8)len;
+
+ retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL);
+ kfree(buf);
+ if (retval != USB_STOR_TRANSPORT_GOOD) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int do_config_autodelink(struct us_data *us, int enable, int force)
+{
+ int retval;
+ u8 value;
+
+ retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (enable) {
+ if (force)
+ value |= 0x03;
+ else
+ value |= 0x01;
+ } else {
+ value &= ~0x03;
+ }
+
+ usb_stor_dbg(us, "set 0xfe47 to 0x%x\n", value);
+
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static int config_autodelink_after_power_on(struct us_data *us)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ int retval;
+ u8 value;
+
+ if (!CHK_AUTO_DELINK(chip))
+ return 0;
+
+ retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (auto_delink_en) {
+ CLR_BIT(value, 0);
+ CLR_BIT(value, 1);
+ SET_BIT(value, 2);
+
+ if (CHECK_ID(chip, 0x0138, 0x3882))
+ CLR_BIT(value, 2);
+
+ SET_BIT(value, 7);
+
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ retval = enable_oscillator(us);
+ if (retval == 0)
+ (void)do_config_autodelink(us, 1, 0);
+ } else {
+ /* Autodelink controlled by firmware */
+
+ SET_BIT(value, 2);
+
+ if (CHECK_ID(chip, 0x0138, 0x3882))
+ CLR_BIT(value, 2);
+
+ if (CHECK_ID(chip, 0x0159, 0x5889) ||
+ CHECK_ID(chip, 0x0138, 0x3880)) {
+ CLR_BIT(value, 0);
+ CLR_BIT(value, 7);
+ }
+
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (CHECK_ID(chip, 0x0159, 0x5888)) {
+ value = 0xFF;
+ retval = rts51x_write_mem(us, 0xFE79, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ value = 0x01;
+ retval = rts51x_write_mem(us, 0x48, &value, 1);
+ if (retval < 0)
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int config_autodelink_before_power_down(struct us_data *us)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ int retval;
+ u8 value;
+
+ if (!CHK_AUTO_DELINK(chip))
+ return 0;
+
+ if (auto_delink_en) {
+ retval = rts51x_read_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ SET_BIT(value, 2);
+ retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (CHECK_ID(chip, 0x0159, 0x5888)) {
+ value = 0x01;
+ retval = rts51x_write_mem(us, 0x48, &value, 1);
+ if (retval < 0)
+ return -EIO;
+ }
+
+ retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ SET_BIT(value, 0);
+ if (CHECK_ID(chip, 0x0138, 0x3882))
+ SET_BIT(value, 2);
+ retval = rts51x_write_mem(us, 0xFE77, &value, 1);
+ if (retval < 0)
+ return -EIO;
+ } else {
+ if (CHECK_ID(chip, 0x0159, 0x5889) ||
+ CHECK_ID(chip, 0x0138, 0x3880) ||
+ CHECK_ID(chip, 0x0138, 0x3882)) {
+ retval = rts51x_read_mem(us, 0xFE47, &value, 1);
+ if (retval < 0)
+ return -EIO;
+
+ if (CHECK_ID(chip, 0x0159, 0x5889) ||
+ CHECK_ID(chip, 0x0138, 0x3880)) {
+ SET_BIT(value, 0);
+ SET_BIT(value, 7);
+ }
+
+ if (CHECK_ID(chip, 0x0138, 0x3882))
+ SET_BIT(value, 2);
+
+ /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
+ retval = __do_config_autodelink(us, &value, 1);
+ if (retval < 0)
+ return -EIO;
+ }
+
+ if (CHECK_ID(chip, 0x0159, 0x5888)) {
+ value = 0x01;
+ retval = rts51x_write_mem(us, 0x48, &value, 1);
+ if (retval < 0)
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static void fw5895_init(struct us_data *us)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ int retval;
+ u8 val;
+
+ if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
+ usb_stor_dbg(us, "Not the specified device, return immediately!\n");
+ } else {
+ retval = rts51x_read_mem(us, 0xFD6F, &val, 1);
+ if (retval == STATUS_SUCCESS && (val & 0x1F) == 0) {
+ val = 0x1F;
+ retval = rts51x_write_mem(us, 0xFD70, &val, 1);
+ if (retval != STATUS_SUCCESS)
+ usb_stor_dbg(us, "Write memory fail\n");
+ } else {
+ usb_stor_dbg(us, "Read memory fail, OR (val & 0x1F) != 0\n");
+ }
+ }
+}
+
+#ifdef CONFIG_REALTEK_AUTOPM
+static void fw5895_set_mmc_wp(struct us_data *us)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ int retval;
+ u8 buf[13];
+
+ if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
+ usb_stor_dbg(us, "Not the specified device, return immediately!\n");
+ } else {
+ retval = rts51x_read_mem(us, 0xFD6F, buf, 1);
+ if (retval == STATUS_SUCCESS && (buf[0] & 0x24) == 0x24) {
+ /* SD Exist and SD WP */
+ retval = rts51x_read_mem(us, 0xD04E, buf, 1);
+ if (retval == STATUS_SUCCESS) {
+ buf[0] |= 0x04;
+ retval = rts51x_write_mem(us, 0xFD70, buf, 1);
+ if (retval != STATUS_SUCCESS)
+ usb_stor_dbg(us, "Write memory fail\n");
+ } else {
+ usb_stor_dbg(us, "Read memory fail\n");
+ }
+ } else {
+ usb_stor_dbg(us, "Read memory fail, OR (buf[0]&0x24)!=0x24\n");
+ }
+ }
+}
+
+static void rts51x_modi_suspend_timer(struct rts51x_chip *chip)
+{
+ struct us_data *us = chip->us;
+
+ usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
+
+ chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay);
+ mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires);
+}
+
+static void rts51x_suspend_timer_fn(unsigned long data)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)data;
+ struct us_data *us = chip->us;
+
+ switch (rts51x_get_stat(chip)) {
+ case RTS51X_STAT_INIT:
+ case RTS51X_STAT_RUN:
+ rts51x_modi_suspend_timer(chip);
+ break;
+ case RTS51X_STAT_IDLE:
+ case RTS51X_STAT_SS:
+ usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
+
+ if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) {
+ usb_stor_dbg(us, "Ready to enter SS state\n");
+ rts51x_set_stat(chip, RTS51X_STAT_SS);
+ /* ignore mass storage interface's children */
+ pm_suspend_ignore_children(&us->pusb_intf->dev, true);
+ usb_autopm_put_interface_async(us->pusb_intf);
+ usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
+ }
+ break;
+ default:
+ usb_stor_dbg(us, "Unknown state !!!\n");
+ break;
+ }
+}
+
+static inline int working_scsi(struct scsi_cmnd *srb)
+{
+ if ((srb->cmnd[0] == TEST_UNIT_READY) ||
+ (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
+ static int card_first_show = 1;
+ static u8 media_not_present[] = { 0x70, 0, 0x02, 0, 0, 0, 0,
+ 10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0
+ };
+ static u8 invalid_cmd_field[] = { 0x70, 0, 0x05, 0, 0, 0, 0,
+ 10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0
+ };
+ int ret;
+
+ if (working_scsi(srb)) {
+ usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
+
+ if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) {
+ ret = usb_autopm_get_interface(us->pusb_intf);
+ usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
+ }
+ if (rts51x_get_stat(chip) != RTS51X_STAT_RUN)
+ rts51x_set_stat(chip, RTS51X_STAT_RUN);
+ chip->proto_handler_backup(srb, us);
+ } else {
+ if (rts51x_get_stat(chip) == RTS51X_STAT_SS) {
+ usb_stor_dbg(us, "NOT working scsi\n");
+ if ((srb->cmnd[0] == TEST_UNIT_READY) &&
+ (chip->pwr_state == US_SUSPEND)) {
+ if (TST_LUN_READY(chip, srb->device->lun)) {
+ srb->result = SAM_STAT_GOOD;
+ } else {
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ memcpy(srb->sense_buffer,
+ media_not_present,
+ US_SENSE_SIZE);
+ }
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
+ goto out;
+ }
+ if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+ int prevent = srb->cmnd[4] & 0x1;
+ if (prevent) {
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ memcpy(srb->sense_buffer,
+ invalid_cmd_field,
+ US_SENSE_SIZE);
+ } else {
+ srb->result = SAM_STAT_GOOD;
+ }
+ usb_stor_dbg(us, "ALLOW_MEDIUM_REMOVAL\n");
+ goto out;
+ }
+ } else {
+ usb_stor_dbg(us, "NOT working scsi, not SS\n");
+ chip->proto_handler_backup(srb, us);
+ /* Check whether card is plugged in */
+ if (srb->cmnd[0] == TEST_UNIT_READY) {
+ if (srb->result == SAM_STAT_GOOD) {
+ SET_LUN_READY(chip, srb->device->lun);
+ if (card_first_show) {
+ card_first_show = 0;
+ fw5895_set_mmc_wp(us);
+ }
+ } else {
+ CLR_LUN_READY(chip, srb->device->lun);
+ card_first_show = 1;
+ }
+ }
+ if (rts51x_get_stat(chip) != RTS51X_STAT_IDLE)
+ rts51x_set_stat(chip, RTS51X_STAT_IDLE);
+ }
+ }
+out:
+ usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
+ if (rts51x_get_stat(chip) == RTS51X_STAT_RUN)
+ rts51x_modi_suspend_timer(chip);
+}
+
+static int realtek_cr_autosuspend_setup(struct us_data *us)
+{
+ struct rts51x_chip *chip;
+ struct rts51x_status *status = NULL;
+ u8 buf[16];
+ int retval;
+
+ chip = (struct rts51x_chip *)us->extra;
+ chip->support_auto_delink = 0;
+ chip->pwr_state = US_RESUME;
+ chip->lun_ready = 0;
+ rts51x_set_stat(chip, RTS51X_STAT_INIT);
+
+ retval = rts51x_read_status(us, 0, buf, 16, &(chip->status_len));
+ if (retval != STATUS_SUCCESS) {
+ usb_stor_dbg(us, "Read status fail\n");
+ return -EIO;
+ }
+ status = chip->status;
+ status->vid = ((u16) buf[0] << 8) | buf[1];
+ status->pid = ((u16) buf[2] << 8) | buf[3];
+ status->cur_lun = buf[4];
+ status->card_type = buf[5];
+ status->total_lun = buf[6];
+ status->fw_ver = ((u16) buf[7] << 8) | buf[8];
+ status->phy_exist = buf[9];
+ status->multi_flag = buf[10];
+ status->multi_card = buf[11];
+ status->log_exist = buf[12];
+ if (chip->status_len == 16) {
+ status->detailed_type.detailed_type1 = buf[13];
+ status->function[0] = buf[14];
+ status->function[1] = buf[15];
+ }
+
+ /* back up the proto_handler in us->extra */
+ chip = (struct rts51x_chip *)(us->extra);
+ chip->proto_handler_backup = us->proto_handler;
+ /* Set the autosuspend_delay to 0 */
+ pm_runtime_set_autosuspend_delay(&us->pusb_dev->dev, 0);
+ /* override us->proto_handler setted in get_protocol() */
+ us->proto_handler = rts51x_invoke_transport;
+
+ chip->timer_expires = 0;
+ setup_timer(&chip->rts51x_suspend_timer, rts51x_suspend_timer_fn,
+ (unsigned long)chip);
+ fw5895_init(us);
+
+ /* enable autosuspend funciton of the usb device */
+ usb_enable_autosuspend(us->pusb_dev);
+
+ return 0;
+}
+#endif
+
+static void realtek_cr_destructor(void *extra)
+{
+ struct rts51x_chip *chip = extra;
+
+ if (!chip)
+ return;
+
+#ifdef CONFIG_REALTEK_AUTOPM
+ if (ss_en) {
+ del_timer(&chip->rts51x_suspend_timer);
+ chip->timer_expires = 0;
+ }
+#endif
+ kfree(chip->status);
+}
+
+#ifdef CONFIG_PM
+static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ /* wait until no command is running */
+ mutex_lock(&us->dev_mutex);
+
+ config_autodelink_before_power_down(us);
+
+ mutex_unlock(&us->dev_mutex);
+
+ return 0;
+}
+
+static int realtek_cr_resume(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ fw5895_init(us);
+ config_autodelink_after_power_on(us);
+
+ return 0;
+}
+#else
+#define realtek_cr_suspend NULL
+#define realtek_cr_resume NULL
+#endif
+
+static int init_realtek_cr(struct us_data *us)
+{
+ struct rts51x_chip *chip;
+ int size, i, retval;
+
+ chip = kzalloc(sizeof(struct rts51x_chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ us->extra = chip;
+ us->extra_destructor = realtek_cr_destructor;
+ us->max_lun = chip->max_lun = rts51x_get_max_lun(us);
+ chip->us = us;
+
+ usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun);
+
+ size = (chip->max_lun + 1) * sizeof(struct rts51x_status);
+ chip->status = kzalloc(size, GFP_KERNEL);
+ if (!chip->status)
+ goto INIT_FAIL;
+
+ for (i = 0; i <= (int)(chip->max_lun); i++) {
+ retval = rts51x_check_status(us, (u8) i);
+ if (retval < 0)
+ goto INIT_FAIL;
+ }
+
+ if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
+ CHECK_FW_VER(chip, 0x5901))
+ SET_AUTO_DELINK(chip);
+ if (STATUS_LEN(chip) == 16) {
+ if (SUPPORT_AUTO_DELINK(chip))
+ SET_AUTO_DELINK(chip);
+ }
+#ifdef CONFIG_REALTEK_AUTOPM
+ if (ss_en)
+ realtek_cr_autosuspend_setup(us);
+#endif
+
+ usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag);
+
+ (void)config_autodelink_after_power_on(us);
+
+ return 0;
+
+INIT_FAIL:
+ if (us->extra) {
+ kfree(chip->status);
+ kfree(us->extra);
+ us->extra = NULL;
+ }
+
+ return -EIO;
+}
+
+static int realtek_cr_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ dev_dbg(&intf->dev, "Probe Realtek Card Reader!\n");
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - realtek_cr_ids) +
+ realtek_cr_unusual_dev_list);
+ if (result)
+ return result;
+
+ result = usb_stor_probe2(us);
+
+ return result;
+}
+
+static struct usb_driver realtek_cr_driver = {
+ .name = "ums-realtek",
+ .probe = realtek_cr_probe,
+ .disconnect = usb_stor_disconnect,
+ /* .suspend = usb_stor_suspend, */
+ /* .resume = usb_stor_resume, */
+ .reset_resume = usb_stor_reset_resume,
+ .suspend = realtek_cr_suspend,
+ .resume = realtek_cr_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = realtek_cr_ids,
+ .soft_unbind = 1,
+ .supports_autosuspend = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(realtek_cr_driver);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 4837524eada..866b5df36ed 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.26 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -45,8 +43,8 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -60,23 +58,56 @@
#include "transport.h"
#include "protocol.h"
+/* Vendor IDs for companies that seem to include the READ CAPACITY bug
+ * in all their devices
+ */
+#define VENDOR_ID_NOKIA 0x0421
+#define VENDOR_ID_NIKON 0x04b0
+#define VENDOR_ID_PENTAX 0x0a17
+#define VENDOR_ID_MOTOROLA 0x22b8
+
/***********************************************************************
* Host functions
***********************************************************************/
static const char* host_info(struct Scsi_Host *host)
{
- return "SCSI emulation for USB Mass Storage devices";
+ struct us_data *us = host_to_us(host);
+ return us->scsi_name;
}
static int slave_alloc (struct scsi_device *sdev)
{
+ struct us_data *us = host_to_us(sdev->host);
+
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
sdev->inquiry_len = 36;
+
+ /* USB has unusual DMA-alignment requirements: Although the
+ * starting address of each scatter-gather element doesn't matter,
+ * the length of each element except the last must be divisible
+ * by the Bulk maxpacket value. There's currently no way to
+ * express this by block-layer constraints, so we'll cop out
+ * and simply require addresses to be aligned at 512-byte
+ * boundaries. This is okay since most block I/O involves
+ * hardware sectors that are multiples of 512 bytes in length,
+ * and since host controllers up through USB 2.0 have maxpacket
+ * values no larger than 512.
+ *
+ * But it doesn't suffice for Wireless USB, where Bulk maxpacket
+ * values can be as large as 2048. To make that work properly
+ * will require changes to the block layer.
+ */
+ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
+ /* Tell the SCSI layer if we know there is more than one LUN */
+ if (us->protocol == USB_PR_BULK && us->max_lun > 0)
+ sdev->sdev_bflags |= BLIST_FORCELUN;
+
return 0;
}
@@ -84,52 +115,60 @@ static int slave_configure(struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
- /* Scatter-gather buffers (all but the last) must have a length
- * divisible by the bulk maxpacket size. Otherwise a data packet
- * would end up being short, causing a premature end to the data
- * transfer. Since high-speed bulk pipes have a maxpacket size
- * of 512, we'll use that as the scsi device queue's DMA alignment
- * mask. Guaranteeing proper alignment of the first buffer will
- * have the desired effect because, except at the beginning and
- * the end, scatter-gather buffers follow page boundaries. */
- blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
-
- /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
- * what is originally reported. We need this to avoid confusing
- * the SCSI layer with devices that report 0 or 1, but need 10-byte
- * commands (ala ATAPI devices behind certain bridges, or devices
- * which simply have broken INQUIRY data).
- *
- * NOTE: This means /dev/sg programs (ala cdrecord) will get the
- * actual information. This seems to be the preference for
- * programs like that.
- *
- * NOTE: This also means that /proc/scsi/scsi and sysfs may report
- * the actual value or the modified one, depending on where the
- * data comes from.
+ /* Many devices have trouble transferring more than 32KB at a time,
+ * while others have trouble with more than 64K. At this time we
+ * are limiting both to 32K (64 sectores).
+ */
+ if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) {
+ unsigned int max_sectors = 64;
+
+ if (us->fflags & US_FL_MAX_SECTORS_MIN)
+ max_sectors = PAGE_CACHE_SIZE >> 9;
+ if (queue_max_hw_sectors(sdev->request_queue) > max_sectors)
+ blk_queue_max_hw_sectors(sdev->request_queue,
+ max_sectors);
+ } else if (sdev->type == TYPE_TAPE) {
+ /* Tapes need much higher max_sector limits, so just
+ * raise it to the maximum possible (4 GB / 512) and
+ * let the queue segment size sort out the real limit.
+ */
+ blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF);
+ }
+
+ /* Some USB host controllers can't do DMA; they have to use PIO.
+ * They indicate this by setting their dma_mask to NULL. For
+ * such controllers we need to make sure the block layer sets
+ * up bounce buffers in addressable memory.
*/
- if (sdev->scsi_level < SCSI_2)
- sdev->scsi_level = SCSI_2;
-
- /* According to the technical support people at Genesys Logic,
- * devices using their chips have problems transferring more than
- * 32 KB at a time. In practice people have found that 64 KB
- * works okay and that's what Windows does. But we'll be
- * conservative; people can always use the sysfs interface to
- * increase max_sectors. */
- if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS &&
- sdev->request_queue->max_sectors > 64)
- blk_queue_max_sectors(sdev->request_queue, 64);
+ if (!us->pusb_dev->bus->controller->dma_mask)
+ blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
/* We can't put these settings in slave_alloc() because that gets
* called before the device type is known. Consequently these
* settings can't be overridden via the scsi devinfo mechanism. */
if (sdev->type == TYPE_DISK) {
+ /* Some vendors seem to put the READ CAPACITY bug into
+ * all their devices -- primarily makers of cell phones
+ * and digital cameras. Since these devices always use
+ * flash media and can be expected to have an even number
+ * of sectors, we will always enable the CAPACITY_HEURISTICS
+ * flag unless told otherwise. */
+ switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) {
+ case VENDOR_ID_NOKIA:
+ case VENDOR_ID_NIKON:
+ case VENDOR_ID_PENTAX:
+ case VENDOR_ID_MOTOROLA:
+ if (!(us->fflags & (US_FL_FIX_CAPACITY |
+ US_FL_CAPACITY_OK)))
+ us->fflags |= US_FL_CAPACITY_HEURISTICS;
+ break;
+ }
+
/* Disk-type devices use MODE SENSE(6) if the protocol
* (SubClass) is Transparent SCSI, otherwise they use
* MODE SENSE(10). */
- if (us->subclass != US_SC_SCSI)
+ if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB)
sdev->use_10_for_ms = 1;
/* Many disks only accept MODE SENSE transfer lengths of
@@ -143,26 +182,50 @@ static int slave_configure(struct scsi_device *sdev)
* majority of devices work fine, but a few still can't
* handle it. The sd driver will simply assume those
* devices are write-enabled. */
- if (us->flags & US_FL_NO_WP_DETECT)
+ if (us->fflags & US_FL_NO_WP_DETECT)
sdev->skip_ms_page_3f = 1;
/* A number of devices have problems with MODE SENSE for
* page x08, so we will skip it. */
sdev->skip_ms_page_8 = 1;
+ /* Some devices don't handle VPD pages correctly */
+ sdev->skip_vpd_pages = 1;
+
+ /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */
+ sdev->no_report_opcodes = 1;
+
+ /* Do not attempt to use WRITE SAME */
+ sdev->no_write_same = 1;
+
/* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */
- if (us->flags & US_FL_FIX_CAPACITY)
+ if (us->fflags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
- /* Some devices report a SCSI revision level above 2 but are
- * unable to handle the REPORT LUNS command (for which
- * support is mandatory at level 3). Since we already have
- * a Get-Max-LUN request, we won't lose much by setting the
- * revision level down to 2. The only devices that would be
- * affected are those with sparse LUNs. */
- sdev->scsi_level = SCSI_2;
+ /* A few disks have two indistinguishable version, one of
+ * which reports the correct capacity and the other does not.
+ * The sd driver has to guess which is the case. */
+ if (us->fflags & US_FL_CAPACITY_HEURISTICS)
+ sdev->guess_capacity = 1;
+
+ /* Some devices cannot handle READ_CAPACITY_16 */
+ if (us->fflags & US_FL_NO_READ_CAPACITY_16)
+ sdev->no_read_capacity_16 = 1;
+
+ /*
+ * Many devices do not respond properly to READ_CAPACITY_16.
+ * Tell the SCSI layer to try READ_CAPACITY_10 first.
+ * However some USB 3.0 drive enclosures return capacity
+ * modulo 2TB. Those must use READ_CAPACITY_16
+ */
+ if (!(us->fflags & US_FL_NEEDS_CAP16))
+ sdev->try_rc_10_first = 1;
+
+ /* assume SPC3 or latter devices support sense size > 18 */
+ if (sdev->scsi_level > SCSI_SPC_2)
+ us->fflags |= US_FL_SANE_SENSE;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
@@ -172,17 +235,56 @@ static int slave_configure(struct scsi_device *sdev)
* is an occasional series of retries that will all fail. */
sdev->retry_hwerror = 1;
+ /* USB disks should allow restart. Some drives spin down
+ * automatically, requiring a START-STOP UNIT command. */
+ sdev->allow_restart = 1;
+
+ /* Some USB cardreaders have trouble reading an sdcard's last
+ * sector in a larger then 1 sector read, since the performance
+ * impact is negible we set this flag for all USB disks */
+ sdev->last_sector_bug = 1;
+
+ /* Enable last-sector hacks for single-target devices using
+ * the Bulk-only transport, unless we already know the
+ * capacity will be decremented or is correct. */
+ if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
+ US_FL_SCM_MULT_TARG)) &&
+ us->protocol == USB_PR_BULK)
+ us->use_last_sector_hacks = 1;
+
+ /* Check if write cache default on flag is set or not */
+ if (us->fflags & US_FL_WRITE_CACHE)
+ sdev->wce_default_on = 1;
+
+ /* A few buggy USB-ATA bridges don't understand FUA */
+ if (us->fflags & US_FL_BROKEN_FUA)
+ sdev->broken_fua = 1;
+
} else {
/* Non-disk-type devices don't need to blacklist any pages
* or to force 192-byte transfer lengths for MODE SENSE.
* But they do need to use MODE SENSE(10). */
sdev->use_10_for_ms = 1;
+
+ /* Some (fake) usb cdrom devices don't like READ_DISC_INFO */
+ if (us->fflags & US_FL_NO_READ_DISC_INFO)
+ sdev->no_read_disc_info = 1;
}
+ /* The CB and CBI transports have no way to pass LUN values
+ * other than the bits in the second byte of a CDB. But those
+ * bits don't get set to the LUN value if the device reports
+ * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily
+ * be single-LUN.
+ */
+ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) &&
+ sdev->scsi_level == SCSI_UNKNOWN)
+ us->max_lun = 0;
+
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command, so suppress those commands. */
- if (us->flags & US_FL_NOT_LOCKABLE)
+ if (us->fflags & US_FL_NOT_LOCKABLE)
sdev->lockable = 0;
/* this is to satisfy the compiler, tho I don't think the
@@ -190,25 +292,50 @@ static int slave_configure(struct scsi_device *sdev)
return 0;
}
+static int target_alloc(struct scsi_target *starget)
+{
+ struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
+
+ /*
+ * Some USB drives don't support REPORT LUNS, even though they
+ * report a SCSI revision level above 2. Tell the SCSI layer
+ * not to issue that command; it will perform a normal sequential
+ * scan instead.
+ */
+ starget->no_report_luns = 1;
+
+ /*
+ * The UFI spec treats the Peripheral Qualifier bits in an
+ * INQUIRY result as reserved and requires devices to set them
+ * to 0. However the SCSI spec requires these bits to be set
+ * to 3 to indicate when a LUN is not present.
+ *
+ * Let the scanning code know if this target merely sets
+ * Peripheral Device Type to 0x1f to indicate no LUN.
+ */
+ if (us->subclass == USB_SC_UFI)
+ starget->pdt_1f_for_no_lun = 1;
+
+ return 0;
+}
+
/* queue a command */
/* This is always called with scsi_lock(host) held */
-static int queuecommand(struct scsi_cmnd *srb,
+static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __FUNCTION__);
-
/* check for state-transition errors */
if (us->srb != NULL) {
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
- __FUNCTION__, us->srb);
+ __func__, us->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
/* fail the command if we are disconnecting */
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- US_DEBUGP("Fail command during disconnect\n");
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ usb_stor_dbg(us, "Fail command during disconnect\n");
srb->result = DID_NO_CONNECT << 16;
done(srb);
return 0;
@@ -217,11 +344,13 @@ static int queuecommand(struct scsi_cmnd *srb,
/* enqueue the command and wake up the control thread */
srb->scsi_done = done;
us->srb = srb;
- up(&(us->sema));
+ complete(&us->cmnd_ready);
return 0;
}
+static DEF_SCSI_QCMD(queuecommand)
+
/***********************************************************************
* Error handling functions
***********************************************************************/
@@ -231,7 +360,7 @@ static int command_abort(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __FUNCTION__);
+ usb_stor_dbg(us, "%s called\n", __func__);
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. */
@@ -240,7 +369,7 @@ static int command_abort(struct scsi_cmnd *srb)
/* Is this command still active? */
if (us->srb != srb) {
scsi_unlock(us_to_host(us));
- US_DEBUGP ("-- nothing to abort\n");
+ usb_stor_dbg(us, "-- nothing to abort\n");
return FAILED;
}
@@ -249,9 +378,9 @@ static int command_abort(struct scsi_cmnd *srb)
* with the reset). Note that we must retain the host lock while
* calling usb_stor_stop_transport(); otherwise it might interfere
* with an auto-reset that begins as soon as we release the lock. */
- set_bit(US_FLIDX_TIMED_OUT, &us->flags);
- if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
- set_bit(US_FLIDX_ABORTING, &us->flags);
+ set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
+ if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) {
+ set_bit(US_FLIDX_ABORTING, &us->dflags);
usb_stor_stop_transport(us);
}
scsi_unlock(us_to_host(us));
@@ -268,12 +397,12 @@ static int device_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __FUNCTION__);
+ usb_stor_dbg(us, "%s called\n", __func__);
/* lock the device pointers and do the reset */
- down(&(us->dev_semaphore));
+ mutex_lock(&(us->dev_mutex));
result = us->transport_reset(us);
- up(&(us->dev_semaphore));
+ mutex_unlock(&us->dev_mutex);
return result < 0 ? FAILED : SUCCESS;
}
@@ -284,12 +413,9 @@ static int bus_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __FUNCTION__);
+ usb_stor_dbg(us, "%s called\n", __func__);
- down(&(us->dev_semaphore));
result = usb_stor_port_reset(us);
- up(&(us->dev_semaphore));
-
return result < 0 ? FAILED : SUCCESS;
}
@@ -302,7 +428,7 @@ void usb_stor_report_device_reset(struct us_data *us)
struct Scsi_Host *host = us_to_host(us);
scsi_report_device_reset(host, 0, 0);
- if (us->flags & US_FL_SCM_MULT_TARG) {
+ if (us->fflags & US_FL_SCM_MULT_TARG) {
for (i = 1; i < host->max_id; ++i)
scsi_report_device_reset(host, 0, i);
}
@@ -310,32 +436,35 @@ void usb_stor_report_device_reset(struct us_data *us)
/* Report a driver-initiated bus reset to the SCSI layer.
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
- * The caller must own the SCSI host lock. */
+ * The caller must not own the SCSI host lock. */
void usb_stor_report_bus_reset(struct us_data *us)
{
- scsi_report_bus_reset(us_to_host(us), 0);
+ struct Scsi_Host *host = us_to_host(us);
+
+ scsi_lock(host);
+ scsi_report_bus_reset(host, 0);
+ scsi_unlock(host);
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
+static int write_info(struct Scsi_Host *host, char *buffer, int length)
+{
+ /* if someone is sending us data, just throw it away */
+ return length;
+}
+
/* we use this macro to help us write into the buffer */
#undef SPRINTF
-#define SPRINTF(args...) \
- do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+#define SPRINTF(args...) seq_printf(m, ## args)
-static int proc_info (struct Scsi_Host *host, char *buffer,
- char **start, off_t offset, int length, int inout)
+static int show_info (struct seq_file *m, struct Scsi_Host *host)
{
struct us_data *us = host_to_us(host);
- char *pos = buffer;
const char *string;
- /* if someone is sending us data, just throw it away */
- if (inout)
- return length;
-
/* print the controller name */
SPRINTF(" Host scsi%d: usb-storage\n", host->host_no);
@@ -365,28 +494,14 @@ static int proc_info (struct Scsi_Host *host, char *buffer,
SPRINTF(" Transport: %s\n", us->transport_name);
/* show the device flags */
- if (pos < buffer + length) {
- pos += sprintf(pos, " Quirks:");
+ SPRINTF(" Quirks:");
#define US_FLAG(name, value) \
- if (us->flags & value) pos += sprintf(pos, " " #name);
+ if (us->fflags & value) seq_printf(m, " " #name);
US_DO_ALL_FLAGS
#undef US_FLAG
-
- *(pos++) = '\n';
- }
-
- /*
- * Calculate start of next buffer, and return value.
- */
- *start = buffer + offset;
-
- if ((pos - buffer) < offset)
- return (0);
- else if ((pos - buffer - offset) < length)
- return (pos - buffer - offset);
- else
- return (length);
+ seq_putc(m, '\n');
+ return 0;
}
/***********************************************************************
@@ -394,34 +509,32 @@ US_DO_ALL_FLAGS
***********************************************************************/
/* Output routine for the sysfs max_sectors file */
-static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t max_sectors_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
- return sprintf(buf, "%u\n", sdev->request_queue->max_sectors);
+ return sprintf(buf, "%u\n", queue_max_hw_sectors(sdev->request_queue));
}
/* Input routine for the sysfs max_sectors file */
-static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf,
+static ssize_t max_sectors_store(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
unsigned short ms;
- if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
- blk_queue_max_sectors(sdev->request_queue, ms);
- return strlen(buf);
+ if (sscanf(buf, "%hu", &ms) > 0) {
+ blk_queue_max_hw_sectors(sdev->request_queue, ms);
+ return count;
}
- return -EINVAL;
+ return -EINVAL;
}
-
-static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
- store_max_sectors);
+static DEVICE_ATTR_RW(max_sectors);
static struct device_attribute *sysfs_device_attr_list[] = {
- &dev_attr_max_sectors,
- NULL,
- };
+ &dev_attr_max_sectors,
+ NULL,
+};
/*
* this defines our host template, with which we'll allocate hosts
@@ -431,7 +544,8 @@ struct scsi_host_template usb_stor_host_template = {
/* basic userland interface stuff */
.name = "usb-storage",
.proc_name = "usb-storage",
- .proc_info = proc_info,
+ .show_info = show_info,
+ .write_info = write_info,
.info = host_info,
/* command interface -- queued only */
@@ -451,9 +565,10 @@ struct scsi_host_template usb_stor_host_template = {
.slave_alloc = slave_alloc,
.slave_configure = slave_configure,
+ .target_alloc = target_alloc,
/* lots of sg segments can be handled */
- .sg_tablesize = SG_ALL,
+ .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
/* limit the total size of a transfer to 120 KB */
.max_sectors = 240,
@@ -484,4 +599,4 @@ unsigned char usb_stor_sense_invalidCDB[18] = {
[7] = 0x0a, /* additional length */
[12] = 0x24 /* Invalid Field in CDB */
};
-
+EXPORT_SYMBOL_GPL(usb_stor_sense_invalidCDB);
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
index 737e4fa6045..ffa1cca93d2 100644
--- a/drivers/usb/storage/scsiglue.h
+++ b/drivers/usb/storage/scsiglue.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* SCSI Connecting Glue Header File
*
- * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 0ea2f5ab66b..073a2c32ccc 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1,6 +1,5 @@
/* Driver for SanDisk SDDR-09 SmartMedia reader
*
- * $Id: sddr09.c,v 1.24 2002/04/22 03:39:43 mdharm Exp $
* (c) 2000, 2001 Robert Baruch (autophile@starband.net)
* (c) 2002 Andries Brouwer (aeb@cwi.nl)
* Developed with the assistance of:
@@ -41,26 +40,71 @@
* EF: compute checksum (?)
*/
-#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "sddr09.h"
+
+MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader");
+MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>");
+MODULE_LICENSE("GPL");
+
+static int usb_stor_sddr09_dpcm_init(struct us_data *us);
+static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
+static int usb_stor_sddr09_init(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id sddr09_usb_ids[] = {
+# include "unusual_sddr09.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, sddr09_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev sddr09_unusual_dev_list[] = {
+# include "unusual_sddr09.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
-/* #define US_DEBUGP printk */
-
/*
* First some stuff that does not belong here:
* data on SmartMedia and other cards, completely
@@ -133,13 +177,11 @@ static struct nand_flash_dev nand_flash_ids[] = {
{ 0,}
};
-#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
-
static struct nand_flash_dev *
nand_find_id(unsigned char id) {
int i;
- for (i = 0; i < SIZE(nand_flash_ids); i++)
+ for (i = 0; i < ARRAY_SIZE(nand_flash_ids); i++)
if (nand_flash_ids[i].model_id == id)
return &(nand_flash_ids[i]);
return NULL;
@@ -177,11 +219,7 @@ static void nand_init_ecc(void) {
/* compute 3-byte ecc on 256 bytes */
static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
int i, j, a;
- unsigned char par, bit, bits[8];
-
- par = 0;
- for (j = 0; j < 8; j++)
- bits[j] = 0;
+ unsigned char par = 0, bit, bits[8] = {0};
/* collect 16 checksum bits */
for (i = 0; i < 256; i++) {
@@ -214,6 +252,20 @@ static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
* The actual driver starts here.
*/
+struct sddr09_card_info {
+ unsigned long capacity; /* Size of card in bytes */
+ int pagesize; /* Size of page in bytes */
+ int pageshift; /* log2 of pagesize */
+ int blocksize; /* Size of block in pages */
+ int blockshift; /* log2 of blocksize */
+ int blockmask; /* 2^blockshift - 1 */
+ int *lba_to_pba; /* logical to physical map */
+ int *pba_to_lba; /* physical to logical map */
+ int lbact; /* number of available pages */
+ int flags;
+#define SDDR09_WP 1 /* write protected */
+};
+
/*
* On my 16MB card, control blocks have size 64 (16 real control bytes,
* and 48 junk bytes). In reality of course the card uses 16 control bytes,
@@ -237,7 +289,7 @@ static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
#define SPARE 0xfffffffe
#define UNUSABLE 0xfffffffd
-static int erase_bad_lba_entries = 0;
+static const int erase_bad_lba_entries = 0;
/* send vendor interface command (0x41) */
/* called for requests 0, 1, 8 */
@@ -260,8 +312,11 @@ sddr09_send_command(struct us_data *us,
rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
0, 0, xfer_data, xfer_len);
- return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD :
- USB_STOR_TRANSPORT_ERROR);
+ switch (rc) {
+ case USB_STOR_XFER_GOOD: return 0;
+ case USB_STOR_XFER_STALLED: return -EPIPE;
+ default: return -EIO;
+ }
}
static int
@@ -286,7 +341,7 @@ sddr09_test_unit_ready(struct us_data *us) {
result = sddr09_send_scsi_command(us, command, 6);
- US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
+ usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result);
return result;
}
@@ -308,20 +363,12 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
command[4] = buflen;
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("request sense failed\n");
+ if (result)
return result;
- }
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
sensebuf, buflen, NULL);
- if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("request sense bulk in failed\n");
- return USB_STOR_TRANSPORT_ERROR;
- } else {
- US_DEBUGP("request sense worked\n");
- return USB_STOR_TRANSPORT_GOOD;
- }
+ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
}
/*
@@ -369,9 +416,9 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
- x, result);
+ if (result) {
+ usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n",
+ x, result);
return result;
}
@@ -379,11 +426,11 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
buf, bulklen, use_sg, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
- x, result);
- return USB_STOR_TRANSPORT_ERROR;
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n",
+ x, result);
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
/*
@@ -441,8 +488,7 @@ sddr09_read22(struct us_data *us, unsigned long fromaddress,
int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
- US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n",
- nr_of_pages, bulklen);
+ usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen);
return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
buf, use_sg);
}
@@ -485,7 +531,7 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) {
unsigned char *command = us->iobuf;
int result;
- US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress);
+ usb_stor_dbg(us, "erase address %lu\n", Eaddress);
memset(command, 0, 12);
command[0] = 0xEA;
@@ -497,9 +543,9 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) {
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
- US_DEBUGP("Result for send_control in sddr09_erase %d\n",
- result);
+ if (result)
+ usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n",
+ result);
return result;
}
@@ -555,9 +601,9 @@ sddr09_writeX(struct us_data *us,
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
- result);
+ if (result) {
+ usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n",
+ result);
return result;
}
@@ -565,11 +611,11 @@ sddr09_writeX(struct us_data *us,
buf, bulklen, use_sg, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
- result);
- return USB_STOR_TRANSPORT_ERROR;
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n",
+ result);
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
/* erase address, write same address */
@@ -633,26 +679,26 @@ sddr09_read_sg_test_only(struct us_data *us) {
result = sddr09_send_scsi_command(us, command, 4*nsg+3);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
- result);
+ if (result) {
+ usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n",
+ result);
return result;
}
- buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
+ buf = kmalloc(bulklen, GFP_NOIO);
if (!buf)
- return USB_STOR_TRANSPORT_ERROR;
+ return -ENOMEM;
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
buf, bulklen, NULL);
kfree(buf);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
- result);
- return USB_STOR_TRANSPORT_ERROR;
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n",
+ result);
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
#endif
@@ -674,21 +720,20 @@ sddr09_read_status(struct us_data *us, unsigned char *status) {
unsigned char *data = us->iobuf;
int result;
- US_DEBUGP("Reading status...\n");
+ usb_stor_dbg(us, "Reading status...\n");
memset(command, 0, 12);
command[0] = 0xEC;
command[1] = LUNBITS;
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
return result;
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
data, 64, NULL);
*status = data[0];
- return (result == USB_STOR_XFER_GOOD ?
- USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
}
static int
@@ -700,9 +745,17 @@ sddr09_read_data(struct us_data *us,
unsigned char *buffer;
unsigned int lba, maxlba, pba;
unsigned int page, pages;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
int result;
+ // Figure out the initial LBA and page
+ lba = address >> info->blockshift;
+ page = (address & info->blockmask);
+ maxlba = info->capacity >> (info->pageshift + info->blockshift);
+ if (lba >= maxlba)
+ return -EIO;
+
// Since we only read in one block at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
@@ -710,20 +763,16 @@ sddr09_read_data(struct us_data *us,
len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL) {
- printk("sddr09_read_data: Out of memory\n");
- return USB_STOR_TRANSPORT_ERROR;
+ printk(KERN_WARNING "sddr09_read_data: Out of memory\n");
+ return -ENOMEM;
}
- // Figure out the initial LBA and page
- lba = address >> info->blockshift;
- page = (address & info->blockmask);
- maxlba = info->capacity >> (info->pageshift + info->blockshift);
-
// This could be made much more efficient by checking for
// contiguous LBA's. Another exercise left to the student.
- result = USB_STOR_TRANSPORT_GOOD;
- index = offset = 0;
+ result = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -733,9 +782,9 @@ sddr09_read_data(struct us_data *us,
/* Not overflowing capacity? */
if (lba >= maxlba) {
- US_DEBUGP("Error: Requested lba %u exceeds "
- "maximum %u\n", lba, maxlba);
- result = USB_STOR_TRANSPORT_ERROR;
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, maxlba);
+ result = -EIO;
break;
}
@@ -744,33 +793,32 @@ sddr09_read_data(struct us_data *us,
if (pba == UNDEF) { /* this lba was never written */
- US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
- pages, lba, page);
+ usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+ pages, lba, page);
/* This is not really an error. It just means
that the block has never been written.
- Instead of returning USB_STOR_TRANSPORT_ERROR
+ Instead of returning an error
it is better to return all zero data. */
memset(buffer, 0, len);
} else {
- US_DEBUGP("Read %d pages, from PBA %d"
- " (LBA %d) page %d\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+ pages, pba, lba, page);
address = ((pba << info->blockshift) + page) <<
info->pageshift;
result = sddr09_read20(us, address>>1,
pages, info->pageshift, buffer, 0);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
break;
}
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, TO_XFER_BUF);
+ &sg, &offset, TO_XFER_BUF);
page = 0;
lba++;
@@ -829,8 +877,9 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
if (pba == UNDEF) {
pba = sddr09_find_unused_pba(info, lba);
if (!pba) {
- printk("sddr09_write_lba: Out of unused blocks\n");
- return USB_STOR_TRANSPORT_ERROR;
+ printk(KERN_WARNING
+ "sddr09_write_lba: Out of unused blocks\n");
+ return -ENOSPC;
}
info->pba_to_lba[pba] = lba;
info->lba_to_pba[lba] = pba;
@@ -840,8 +889,8 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
if (pba == 1) {
/* Maybe it is impossible to write to PBA 1.
Fake success, but don't do anything. */
- printk("sddr09: avoid writing to pba 1\n");
- return USB_STOR_TRANSPORT_GOOD;
+ printk(KERN_WARNING "sddr09: avoid writing to pba 1\n");
+ return 0;
}
pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
@@ -850,7 +899,7 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
address = (pba << (info->pageshift + info->blockshift));
result = sddr09_read22(us, address>>1, info->blocksize,
info->pageshift, blockbuffer, 0);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
return result;
/* check old contents and fill lba */
@@ -859,14 +908,14 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
cptr = bptr + info->pagesize;
nand_compute_ecc(bptr, ecc);
if (!nand_compare_ecc(cptr+13, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+13, ecc);
}
nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
if (!nand_compare_ecc(cptr+8, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+8, ecc);
}
cptr[6] = cptr[11] = MSB_of(lbap);
@@ -886,22 +935,21 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
nand_store_ecc(cptr+8, ecc);
}
- US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
+ usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba);
result = sddr09_write_inplace(us, address>>1, info->blocksize,
info->pageshift, blockbuffer, 0);
- US_DEBUGP("sddr09_write_inplace returns %d\n", result);
+ usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result);
#if 0
{
unsigned char status = 0;
int result2 = sddr09_read_status(us, &status);
- if (result2 != USB_STOR_TRANSPORT_GOOD)
- US_DEBUGP("sddr09_write_inplace: cannot read status\n");
+ if (result2)
+ usb_stor_dbg(us, "cannot read status\n");
else if (status != 0xc0)
- US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
- status);
+ usb_stor_dbg(us, "status after write: 0x%x\n", status);
}
#endif
@@ -920,13 +968,21 @@ sddr09_write_data(struct us_data *us,
unsigned int sectors) {
struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
- unsigned int lba, page, pages;
+ unsigned int lba, maxlba, page, pages;
unsigned int pagelen, blocklen;
unsigned char *blockbuffer;
unsigned char *buffer;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
int result;
+ // Figure out the initial LBA and page
+ lba = address >> info->blockshift;
+ page = (address & info->blockmask);
+ maxlba = info->capacity >> (info->pageshift + info->blockshift);
+ if (lba >= maxlba)
+ return -EIO;
+
// blockbuffer is used for reading in the old data, overwriting
// with the new data, and performing ECC calculations
@@ -937,8 +993,8 @@ sddr09_write_data(struct us_data *us,
blocklen = (pagelen << info->blockshift);
blockbuffer = kmalloc(blocklen, GFP_NOIO);
if (!blockbuffer) {
- printk("sddr09_write_data: Out of memory\n");
- return USB_STOR_TRANSPORT_ERROR;
+ printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
+ return -ENOMEM;
}
// Since we don't write the user data directly to the device,
@@ -948,17 +1004,14 @@ sddr09_write_data(struct us_data *us,
len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL) {
- printk("sddr09_write_data: Out of memory\n");
+ printk(KERN_WARNING "sddr09_write_data: Out of memory\n");
kfree(blockbuffer);
- return USB_STOR_TRANSPORT_ERROR;
+ return -ENOMEM;
}
- // Figure out the initial LBA and page
- lba = address >> info->blockshift;
- page = (address & info->blockmask);
-
- result = USB_STOR_TRANSPORT_GOOD;
- index = offset = 0;
+ result = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -967,13 +1020,21 @@ sddr09_write_data(struct us_data *us,
pages = min(sectors, info->blocksize - page);
len = (pages << info->pageshift);
+ /* Not overflowing capacity? */
+ if (lba >= maxlba) {
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, maxlba);
+ result = -EIO;
+ break;
+ }
+
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, FROM_XFER_BUF);
+ &sg, &offset, FROM_XFER_BUF);
result = sddr09_write_lba(us, lba, page, pages,
buffer, blockbuffer);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
break;
page = 0;
@@ -994,8 +1055,8 @@ sddr09_read_control(struct us_data *us,
unsigned char *content,
int use_sg) {
- US_DEBUGP("Read control address %lu, blocks %d\n",
- address, blocks);
+ usb_stor_dbg(us, "Read control address %lu, blocks %d\n",
+ address, blocks);
return sddr09_read21(us, address, blocks,
CONTROL_SHIFT, content, use_sg);
@@ -1022,7 +1083,7 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
command[1] = LUNBITS;
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
return result;
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
@@ -1031,8 +1092,7 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
for (i = 0; i < 4; i++)
deviceID[i] = content[i];
- return (result == USB_STOR_XFER_GOOD ?
- USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+ return (result == USB_STOR_XFER_GOOD ? 0 : -EIO);
}
static int
@@ -1041,23 +1101,23 @@ sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
unsigned char status;
result = sddr09_read_status(us, &status);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("sddr09_get_wp: read_status fails\n");
+ if (result) {
+ usb_stor_dbg(us, "read_status fails\n");
return result;
}
- US_DEBUGP("sddr09_get_wp: status 0x%02X", status);
+ usb_stor_dbg(us, "status 0x%02X", status);
if ((status & 0x80) == 0) {
info->flags |= SDDR09_WP; /* write protected */
- US_DEBUGP(" WP");
+ US_DEBUGPX(" WP");
}
if (status & 0x40)
- US_DEBUGP(" Ready");
+ US_DEBUGPX(" Ready");
if (status & LUNBITS)
- US_DEBUGP(" Suspended");
+ US_DEBUGPX(" Suspended");
if (status & 0x1)
- US_DEBUGP(" Error");
- US_DEBUGP("\n");
- return USB_STOR_TRANSPORT_GOOD;
+ US_DEBUGPX(" Error");
+ US_DEBUGPX("\n");
+ return 0;
}
#if 0
@@ -1085,13 +1145,13 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
char blurbtxt[256];
int result;
- US_DEBUGP("Reading capacity...\n");
+ usb_stor_dbg(us, "Reading capacity...\n");
result = sddr09_read_deviceID(us, deviceID);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("Result of read_deviceID is %d\n", result);
- printk("sddr09: could not read card info\n");
+ if (result) {
+ usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
+ printk(KERN_WARNING "sddr09: could not read card info\n");
return NULL;
}
@@ -1132,7 +1192,7 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
sprintf(blurbtxt + strlen(blurbtxt),
", WP");
- printk("%s\n", blurbtxt);
+ printk(KERN_WARNING "%s\n", blurbtxt);
return cardinfo;
}
@@ -1163,7 +1223,7 @@ sddr09_read_map(struct us_data *us) {
alloc_len = (alloc_blocks << CONTROL_SHIFT);
buffer = kmalloc(alloc_len, GFP_NOIO);
if (buffer == NULL) {
- printk("sddr09_read_map: out of memory\n");
+ printk(KERN_WARNING "sddr09_read_map: out of memory\n");
result = -1;
goto done;
}
@@ -1177,7 +1237,7 @@ sddr09_read_map(struct us_data *us) {
info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
- printk("sddr09_read_map: out of memory\n");
+ printk(KERN_WARNING "sddr09_read_map: out of memory\n");
result = -1;
goto done;
}
@@ -1200,7 +1260,7 @@ sddr09_read_map(struct us_data *us) {
us, address>>1,
min(alloc_blocks, numblocks - i),
buffer, 0);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
result = -1;
goto done;
}
@@ -1217,7 +1277,8 @@ sddr09_read_map(struct us_data *us) {
if (ptr[j] != 0)
goto nonz;
info->pba_to_lba[i] = UNUSABLE;
- printk("sddr09: PBA %d has no logical mapping\n", i);
+ printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n",
+ i);
continue;
nonz:
@@ -1230,7 +1291,8 @@ sddr09_read_map(struct us_data *us) {
nonff:
/* normal PBAs start with six FFs */
if (j < 6) {
- printk("sddr09: PBA %d has no logical mapping: "
+ printk(KERN_WARNING
+ "sddr09: PBA %d has no logical mapping: "
"reserved area = %02X%02X%02X%02X "
"data status %02X block status %02X\n",
i, ptr[0], ptr[1], ptr[2], ptr[3],
@@ -1240,7 +1302,8 @@ sddr09_read_map(struct us_data *us) {
}
if ((ptr[6] >> 4) != 0x01) {
- printk("sddr09: PBA %d has invalid address field "
+ printk(KERN_WARNING
+ "sddr09: PBA %d has invalid address field "
"%02X%02X/%02X%02X\n",
i, ptr[6], ptr[7], ptr[11], ptr[12]);
info->pba_to_lba[i] = UNUSABLE;
@@ -1249,7 +1312,8 @@ sddr09_read_map(struct us_data *us) {
/* check even parity */
if (parity[ptr[6] ^ ptr[7]]) {
- printk("sddr09: Bad parity in LBA for block %d"
+ printk(KERN_WARNING
+ "sddr09: Bad parity in LBA for block %d"
" (%02X %02X)\n", i, ptr[6], ptr[7]);
info->pba_to_lba[i] = UNUSABLE;
continue;
@@ -1268,7 +1332,8 @@ sddr09_read_map(struct us_data *us) {
*/
if (lba >= 1000) {
- printk("sddr09: Bad low LBA %d for block %d\n",
+ printk(KERN_WARNING
+ "sddr09: Bad low LBA %d for block %d\n",
lba, i);
goto possibly_erase;
}
@@ -1276,7 +1341,8 @@ sddr09_read_map(struct us_data *us) {
lba += 1000*(i/0x400);
if (info->lba_to_pba[lba] != UNDEF) {
- printk("sddr09: LBA %d seen for PBA %d and %d\n",
+ printk(KERN_WARNING
+ "sddr09: LBA %d seen for PBA %d and %d\n",
lba, info->lba_to_pba[lba], i);
goto possibly_erase;
}
@@ -1317,7 +1383,7 @@ sddr09_read_map(struct us_data *us) {
lbact += ct;
}
info->lbact = lbact;
- US_DEBUGP("Found %d LBA's\n", lbact);
+ usb_stor_dbg(us, "Found %d LBA's\n", lbact);
result = 0;
done:
@@ -1342,47 +1408,71 @@ sddr09_card_info_destructor(void *extra) {
kfree(info->pba_to_lba);
}
-static void
-sddr09_init_card_info(struct us_data *us) {
- if (!us->extra) {
- us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
- if (us->extra) {
- memset(us->extra, 0, sizeof(struct sddr09_card_info));
- us->extra_destructor = sddr09_card_info_destructor;
- }
+static int
+sddr09_common_init(struct us_data *us) {
+ int result;
+
+ /* set the configuration -- STALL is an acceptable response here */
+ if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
+ usb_stor_dbg(us, "active config #%d != 1 ??\n",
+ us->pusb_dev->actconfig->desc.bConfigurationValue);
+ return -EINVAL;
}
+
+ result = usb_reset_configuration(us->pusb_dev);
+ usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result);
+ if (result == -EPIPE) {
+ usb_stor_dbg(us, "-- stall on control interface\n");
+ } else if (result != 0) {
+ /* it's not a stall, but another error -- time to bail */
+ usb_stor_dbg(us, "-- Unknown error. Rejecting device\n");
+ return -EINVAL;
+ }
+
+ us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+ if (!us->extra)
+ return -ENOMEM;
+ us->extra_destructor = sddr09_card_info_destructor;
+
+ nand_init_ecc();
+ return 0;
}
+
/*
* This is needed at a very early stage. If this is not listed in the
* unusual devices list but called from here then LUN 0 of the combo reader
* is not recognized. But I do not know what precisely these calls do.
*/
-int
-sddr09_init(struct us_data *us) {
+static int
+usb_stor_sddr09_dpcm_init(struct us_data *us) {
int result;
unsigned char *data = us->iobuf;
+ result = sddr09_common_init(us);
+ if (result)
+ return result;
+
result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("sddr09_init: send_command fails\n");
+ if (result) {
+ usb_stor_dbg(us, "send_command fails\n");
return result;
}
- US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+ usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
// get 07 02
result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("sddr09_init: 2nd send_command fails\n");
+ if (result) {
+ usb_stor_dbg(us, "2nd send_command fails\n");
return result;
}
- US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+ usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
// get 07 00
result = sddr09_request_sense(us, data, 18);
- if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) {
+ if (result == 0 && data[2] != 0) {
int j;
for (j=0; j<18; j++)
printk(" %02X", data[j]);
@@ -1398,13 +1488,54 @@ sddr09_init(struct us_data *us) {
// test unit ready
- return USB_STOR_TRANSPORT_GOOD; /* not result */
+ return 0; /* not result */
}
/*
+ * Transport for the Microtech DPCM-USB
+ */
+static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int ret;
+
+ usb_stor_dbg(us, "LUN=%d\n", srb->device->lun);
+
+ switch (srb->device->lun) {
+ case 0:
+
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ ret = usb_stor_CB_transport(srb, us);
+ break;
+
+ case 1:
+
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
+
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->device->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->device->lun = 1;
+ break;
+
+ default:
+ usb_stor_dbg(us, "Invalid LUN %d\n", srb->device->lun);
+ ret = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+ return ret;
+}
+
+
+/*
* Transport for the Sandisk SDDR-09
*/
-int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
+static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
{
static unsigned char sensekey = 0, sensecode = 0;
static unsigned char havefakesense = 0;
@@ -1427,13 +1558,6 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
};
info = (struct sddr09_card_info *)us->extra;
- if (!info) {
- nand_init_ecc();
- sddr09_init_card_info(us);
- info = (struct sddr09_card_info *)us->extra;
- if (!info)
- return USB_STOR_TRANSPORT_ERROR;
- }
if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
/* for a faked command, we have to follow with a faked sense */
@@ -1506,8 +1630,8 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
or for all pages. */
/* %% We should check DBD %% */
if (modepage == 0x01 || modepage == 0x3F) {
- US_DEBUGP("SDDR09: Dummy up request for "
- "mode page 0x%x\n", modepage);
+ usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n",
+ modepage);
memcpy(ptr, mode_page_01, sizeof(mode_page_01));
((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
@@ -1533,10 +1657,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("READ_10: read page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "READ_10: read page %d pagect %d\n",
+ page, pages);
- return sddr09_read_data(us, page, pages);
+ result = sddr09_read_data(us, page, pages);
+ return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
+ USB_STOR_TRANSPORT_ERROR);
}
if (srb->cmnd[0] == WRITE_10) {
@@ -1546,10 +1672,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("WRITE_10: write page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n",
+ page, pages);
- return sddr09_write_data(us, page, pages);
+ result = sddr09_write_data(us, page, pages);
+ return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
+ USB_STOR_TRANSPORT_ERROR);
}
/* catch-all for all other commands, except
@@ -1572,16 +1700,16 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
for (i=0; i<12; i++)
sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]);
- US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
+ usb_stor_dbg(us, "Send control for command %s\n", ptr);
result = sddr09_send_scsi_command(us, srb->cmnd, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
- "returns %d\n", result);
- return result;
+ if (result) {
+ usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n",
+ result);
+ return USB_STOR_TRANSPORT_ERROR;
}
- if (srb->request_bufflen == 0)
+ if (scsi_bufflen(srb) == 0)
return USB_STOR_TRANSPORT_GOOD;
if (srb->sc_data_direction == DMA_TO_DEVICE ||
@@ -1589,15 +1717,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE)
? us->send_bulk_pipe : us->recv_bulk_pipe;
- US_DEBUGP("SDDR09: %s %d bytes\n",
- (srb->sc_data_direction == DMA_TO_DEVICE) ?
- "sending" : "receiving",
- srb->request_bufflen);
+ usb_stor_dbg(us, "%s %d bytes\n",
+ (srb->sc_data_direction == DMA_TO_DEVICE) ?
+ "sending" : "receiving",
+ scsi_bufflen(srb));
- result = usb_stor_bulk_transfer_sg(us, pipe,
- srb->request_buffer,
- srb->request_bufflen,
- srb->use_sg, &srb->resid);
+ result = usb_stor_bulk_srb(us, pipe, srb);
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
@@ -1606,3 +1731,53 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
+/*
+ * Initialization routine for the sddr09 subdriver
+ */
+static int
+usb_stor_sddr09_init(struct us_data *us) {
+ return sddr09_common_init(us);
+}
+
+static int sddr09_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - sddr09_usb_ids) + sddr09_unusual_dev_list);
+ if (result)
+ return result;
+
+ if (us->protocol == USB_PR_DPCM_USB) {
+ us->transport_name = "Control/Bulk-EUSB/SDDR09";
+ us->transport = dpcm_transport;
+ us->transport_reset = usb_stor_CB_reset;
+ us->max_lun = 1;
+ } else {
+ us->transport_name = "EUSB/SDDR09";
+ us->transport = sddr09_transport;
+ us->transport_reset = usb_stor_CB_reset;
+ us->max_lun = 0;
+ }
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver sddr09_driver = {
+ .name = "ums-sddr09",
+ .probe = sddr09_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = sddr09_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(sddr09_driver);
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
deleted file mode 100644
index c9d78d6188b..00000000000
--- a/drivers/usb/storage/sddr09.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Driver for SanDisk SDDR-09 SmartMedia reader
- * Header File
- *
- * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $
- *
- * Current development and maintenance by:
- * (c) 2000 Robert Baruch (autophile@dol.net)
- * (c) 2002 Andries Brouwer (aeb@cwi.nl)
- *
- * See sddr09.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _USB_SHUTTLE_EUSB_SDDR09_H
-#define _USB_SHUTTLE_EUSB_SDDR09_H
-
-/* Sandisk SDDR-09 stuff */
-
-extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
-
-struct sddr09_card_info {
- unsigned long capacity; /* Size of card in bytes */
- int pagesize; /* Size of page in bytes */
- int pageshift; /* log2 of pagesize */
- int blocksize; /* Size of block in pages */
- int blockshift; /* log2 of blocksize */
- int blockmask; /* 2^blockshift - 1 */
- int *lba_to_pba; /* logical to physical map */
- int *pba_to_lba; /* physical to logical map */
- int lbact; /* number of available pages */
- int flags;
-#define SDDR09_WP 1 /* write protected */
-};
-
-#endif
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index 8451779f426..aacedef9667 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -1,7 +1,5 @@
/* Driver for SanDisk SDDR-55 SmartMedia reader
*
- * $Id:$
- *
* SDDR55 driver v0.1:
*
* First release
@@ -26,6 +24,7 @@
#include <linux/jiffies.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
@@ -35,7 +34,48 @@
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "sddr55.h"
+
+MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader");
+MODULE_AUTHOR("Simon Munton");
+MODULE_LICENSE("GPL");
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id sddr55_usb_ids[] = {
+# include "unusual_sddr55.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, sddr55_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev sddr55_unusual_dev_list[] = {
+# include "unusual_sddr55.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
@@ -105,8 +145,7 @@ static int sddr55_status(struct us_data *us)
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result for send_command in status %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in status %d\n", result);
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
@@ -167,7 +206,8 @@ static int sddr55_read_data(struct us_data *us,
unsigned long address;
unsigned short pages;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
// Since we only read in one block at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
@@ -178,7 +218,8 @@ static int sddr55_read_data(struct us_data *us,
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR; /* out of memory */
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors>0) {
@@ -194,9 +235,8 @@ static int sddr55_read_data(struct us_data *us,
info->blocksize - page);
len = pages << info->pageshift;
- US_DEBUGP("Read %02X pages, from PBA %04X"
- " (LBA %04X) page %02X\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Read %02X pages, from PBA %04X (LBA %04X) page %02X\n",
+ pages, pba, lba, page);
if (pba == NOT_ALLOCATED) {
/* no pba for this lba, fill with zeroes */
@@ -219,8 +259,8 @@ static int sddr55_read_data(struct us_data *us,
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result for send_command in read_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in read_data %d\n",
+ result);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
@@ -255,7 +295,7 @@ static int sddr55_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, TO_XFER_BUF);
+ &sg, &offset, TO_XFER_BUF);
page = 0;
lba++;
@@ -287,7 +327,8 @@ static int sddr55_write_data(struct us_data *us,
unsigned short pages;
int i;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
/* check if we are allowed to write */
if (info->read_only || info->force_read_only) {
@@ -304,7 +345,8 @@ static int sddr55_write_data(struct us_data *us,
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -322,11 +364,10 @@ static int sddr55_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, FROM_XFER_BUF);
+ &sg, &offset, FROM_XFER_BUF);
- US_DEBUGP("Write %02X pages, to PBA %04X"
- " (LBA %04X) page %02X\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Write %02X pages, to PBA %04X (LBA %04X) page %02X\n",
+ pages, pba, lba, page);
command[4] = 0;
@@ -340,7 +381,7 @@ static int sddr55_write_data(struct us_data *us,
/* set pba to first block in zone lba is in */
pba = (lba / 1000) * 1024;
- US_DEBUGP("No PBA for LBA %04X\n",lba);
+ usb_stor_dbg(us, "No PBA for LBA %04X\n", lba);
if (max_pba > 1024)
max_pba = 1024;
@@ -363,14 +404,15 @@ static int sddr55_write_data(struct us_data *us,
if (pba == -1) {
/* oh dear */
- US_DEBUGP("Couldn't find unallocated block\n");
+ usb_stor_dbg(us, "Couldn't find unallocated block\n");
set_sense_info (3, 0x31, 0); /* medium error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
- US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba);
+ usb_stor_dbg(us, "Allocating PBA %04X for LBA %04X\n",
+ pba, lba);
/* set writing to unallocated block flag */
command[4] = 0x40;
@@ -395,8 +437,8 @@ static int sddr55_write_data(struct us_data *us,
DMA_TO_DEVICE, command, 8);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for send_command in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -409,8 +451,8 @@ static int sddr55_write_data(struct us_data *us,
DMA_TO_DEVICE, buffer, len);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for send_data in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_data in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -422,8 +464,8 @@ static int sddr55_write_data(struct us_data *us,
result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for get_status in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for get_status in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -443,8 +485,8 @@ static int sddr55_write_data(struct us_data *us,
goto leave;
}
- US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
- lba, pba, new_pba);
+ usb_stor_dbg(us, "Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
+ lba, pba, new_pba);
/* update the lba<->pba maps, note new_pba might be the same as pba */
info->lba_to_pba[lba] = new_pba;
@@ -487,8 +529,8 @@ static int sddr55_read_deviceID(struct us_data *us,
command[7] = 0x84;
result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result of send_control for device ID is %d\n",
- result);
+ usb_stor_dbg(us, "Result of send_control for device ID is %d\n",
+ result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -511,32 +553,32 @@ static int sddr55_read_deviceID(struct us_data *us,
}
-int sddr55_reset(struct us_data *us) {
+static int sddr55_reset(struct us_data *us)
+{
return 0;
}
static unsigned long sddr55_get_capacity(struct us_data *us) {
- unsigned char manufacturerID;
- unsigned char deviceID;
+ unsigned char uninitialized_var(manufacturerID);
+ unsigned char uninitialized_var(deviceID);
int result;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
- US_DEBUGP("Reading capacity...\n");
+ usb_stor_dbg(us, "Reading capacity...\n");
result = sddr55_read_deviceID(us,
&manufacturerID,
&deviceID);
- US_DEBUGP("Result of read_deviceID is %d\n",
- result);
+ usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return 0;
- US_DEBUGP("Device ID = %02X\n", deviceID);
- US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
+ usb_stor_dbg(us, "Device ID = %02X\n", deviceID);
+ usb_stor_dbg(us, "Manuf ID = %02X\n", manufacturerID);
info->pageshift = 9;
info->smallpageshift = 0;
@@ -701,12 +743,14 @@ static int sddr55_read_map(struct us_data *us) {
if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED &&
!info->force_read_only) {
- printk("sddr55: map inconsistency at LBA %04X\n", lba + zone * 1000);
+ printk(KERN_WARNING
+ "sddr55: map inconsistency at LBA %04X\n",
+ lba + zone * 1000);
info->force_read_only = 1;
}
if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
- US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
+ usb_stor_dbg(us, "LBA %04X <-> PBA %04X\n", lba, i);
info->lba_to_pba[lba + zone * 1000] = i;
}
@@ -730,7 +774,7 @@ static void sddr55_card_info_destructor(void *extra) {
/*
* Transport for the Sandisk SDDR-55
*/
-int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
+static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result;
static unsigned char inquiry_response[8] = {
@@ -751,18 +795,20 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
struct sddr55_card_info *info;
if (!us->extra) {
- us->extra = kmalloc(
+ us->extra = kzalloc(
sizeof(struct sddr55_card_info), GFP_NOIO);
if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- memset(us->extra, 0, sizeof(struct sddr55_card_info));
us->extra_destructor = sddr55_card_info_destructor;
}
info = (struct sddr55_card_info *)(us->extra);
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]);
+ usb_stor_dbg(us, "request sense %02x/%02x/%02x\n",
+ info->sense_data[2],
+ info->sense_data[12],
+ info->sense_data[13]);
memcpy (ptr, info->sense_data, sizeof info->sense_data);
ptr[0] = 0x70;
@@ -846,13 +892,11 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
- US_DEBUGP(
- "SDDR55: Dummy up request for mode page 1\n");
+ usb_stor_dbg(us, "Dummy up request for mode page 1\n");
return USB_STOR_TRANSPORT_GOOD;
} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
- US_DEBUGP(
- "SDDR55: Dummy up request for all mode pages\n");
+ usb_stor_dbg(us, "Dummy up request for all mode pages\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -862,10 +906,8 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
- US_DEBUGP(
- "SDDR55: %s medium removal. Not that I can do"
- " anything about it...\n",
- (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+ usb_stor_dbg(us, "%s medium removal. Not that I can do anything about it...\n",
+ (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
return USB_STOR_TRANSPORT_GOOD;
@@ -889,8 +931,8 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
if (lba >= info->max_log_blks) {
- US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
- "block %04X\n", lba, info->max_log_blks-1);
+ usb_stor_dbg(us, "Error: Requested LBA %04X exceeds maximum block %04X\n",
+ lba, info->max_log_blks - 1);
set_sense_info (5, 0x24, 0); /* invalid field in command */
@@ -900,15 +942,13 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
pba = info->lba_to_pba[lba];
if (srb->cmnd[0] == WRITE_10) {
- US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X"
- " pages %d\n",
- pba, lba, page, pages);
+ usb_stor_dbg(us, "WRITE_10: write block %04X (LBA %04X) page %01X pages %d\n",
+ pba, lba, page, pages);
return sddr55_write_data(us, lba, page, pages);
} else {
- US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
- " pages %d\n",
- pba, lba, page, pages);
+ usb_stor_dbg(us, "READ_10: read block %04X (LBA %04X) page %01X pages %d\n",
+ pba, lba, page, pages);
return sddr55_read_data(us, lba, page, pages);
}
@@ -928,3 +968,39 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
}
+
+static int sddr55_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - sddr55_usb_ids) + sddr55_unusual_dev_list);
+ if (result)
+ return result;
+
+ us->transport_name = "SDDR55";
+ us->transport = sddr55_transport;
+ us->transport_reset = sddr55_reset;
+ us->max_lun = 0;
+
+ result = usb_stor_probe2(us);
+ return result;
+}
+
+static struct usb_driver sddr55_driver = {
+ .name = "ums-sddr55",
+ .probe = sddr55_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = sddr55_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(sddr55_driver);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 33c55a6261b..008d805c3d2 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1,7 +1,5 @@
/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
*
- * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 2000, 2001 Robert Baruch (autophile@starband.net)
* (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
@@ -43,8 +41,8 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/cdrom.h>
@@ -55,7 +53,100 @@
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#include "shuttle_usbat.h"
+
+MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable");
+MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net>");
+MODULE_LICENSE("GPL");
+
+/* Supported device types */
+#define USBAT_DEV_HP8200 0x01
+#define USBAT_DEV_FLASH 0x02
+
+#define USBAT_EPP_PORT 0x10
+#define USBAT_EPP_REGISTER 0x30
+#define USBAT_ATA 0x40
+#define USBAT_ISA 0x50
+
+/* Commands (need to be logically OR'd with an access type */
+#define USBAT_CMD_READ_REG 0x00
+#define USBAT_CMD_WRITE_REG 0x01
+#define USBAT_CMD_READ_BLOCK 0x02
+#define USBAT_CMD_WRITE_BLOCK 0x03
+#define USBAT_CMD_COND_READ_BLOCK 0x04
+#define USBAT_CMD_COND_WRITE_BLOCK 0x05
+#define USBAT_CMD_WRITE_REGS 0x07
+
+/* Commands (these don't need an access type) */
+#define USBAT_CMD_EXEC_CMD 0x80
+#define USBAT_CMD_SET_FEAT 0x81
+#define USBAT_CMD_UIO 0x82
+
+/* Methods of accessing UIO register */
+#define USBAT_UIO_READ 1
+#define USBAT_UIO_WRITE 0
+
+/* Qualifier bits */
+#define USBAT_QUAL_FCQ 0x20 /* full compare */
+#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */
+
+/* USBAT Flash Media status types */
+#define USBAT_FLASH_MEDIA_NONE 0
+#define USBAT_FLASH_MEDIA_CF 1
+
+/* USBAT Flash Media change types */
+#define USBAT_FLASH_MEDIA_SAME 0
+#define USBAT_FLASH_MEDIA_CHANGED 1
+
+/* USBAT ATA registers */
+#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */
+#define USBAT_ATA_FEATURES 0x11 /* set features (W) */
+#define USBAT_ATA_ERROR 0x11 /* error (R) */
+#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */
+#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */
+#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */
+#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */
+#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */
+#define USBAT_ATA_STATUS 0x17 /* device status (R) */
+#define USBAT_ATA_CMD 0x17 /* device command (W) */
+#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */
+
+/* USBAT User I/O Data registers */
+#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */
+#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */
+ /* CDT = ACKD & !UI1 & !UI0 */
+#define USBAT_UIO_1 0x20 /* I/O 1 */
+#define USBAT_UIO_0 0x10 /* I/O 0 */
+#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */
+#define USBAT_UIO_UI1 0x04 /* Input 1 */
+#define USBAT_UIO_UI0 0x02 /* Input 0 */
+#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
+
+/* USBAT User I/O Enable registers */
+#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */
+#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */
+#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */
+ /* If ACKD=1, set OE1 to 1 also. */
+#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */
+#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */
+
+/* USBAT Features */
+#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */
+#define USBAT_FEAT_U1 0x08
+#define USBAT_FEAT_U0 0x04
+#define USBAT_FEAT_ET1 0x02
+#define USBAT_FEAT_ET2 0x01
+
+struct usbat_info {
+ int devicetype;
+
+ /* Used for Flash readers only */
+ unsigned long sectors; /* total sector count */
+ unsigned long ssize; /* sector size in bytes */
+
+ unsigned char sense_key;
+ unsigned long sense_asc; /* additional sense code */
+ unsigned long sense_ascq; /* additional sense code qualifier */
+};
#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
@@ -66,6 +157,48 @@ static int transferred = 0;
static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
+static int init_usbat_cd(struct us_data *us);
+static int init_usbat_flash(struct us_data *us);
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id usbat_usb_ids[] = {
+# include "unusual_usbat.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usbat_usb_ids);
+
+#undef UNUSUAL_DEV
+
+/*
+ * The flags table
+ */
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
+}
+
+static struct us_unusual_dev usbat_unusual_dev_list[] = {
+# include "unusual_usbat.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
/*
* Convenience function to produce an ATA read/write sectors command
* Use cmd=0x20 for read, cmd=0x30 for write
@@ -131,28 +264,30 @@ static int usbat_write(struct us_data *us,
* Convenience function to perform a bulk read
*/
static int usbat_bulk_read(struct us_data *us,
- unsigned char *data,
- unsigned int len)
+ void* buf,
+ unsigned int len,
+ int use_sg)
{
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("usbat_bulk_read: len = %d\n", len);
- return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL);
+ usb_stor_dbg(us, "len = %d\n", len);
+ return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
}
/*
* Convenience function to perform a bulk write
*/
static int usbat_bulk_write(struct us_data *us,
- unsigned char *data,
- unsigned int len)
+ void* buf,
+ unsigned int len,
+ int use_sg)
{
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("usbat_bulk_write: len = %d\n", len);
- return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL);
+ usb_stor_dbg(us, "len = %d\n", len);
+ return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
}
/*
@@ -177,7 +312,7 @@ static int usbat_get_status(struct us_data *us, unsigned char *status)
int rc;
rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
- US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status));
+ usb_stor_dbg(us, "0x%02X\n", *status);
return rc;
}
@@ -189,9 +324,6 @@ static int usbat_check_status(struct us_data *us)
unsigned char *reply = us->iobuf;
int rc;
- if (!us)
- return USB_STOR_TRANSPORT_ERROR;
-
rc = usbat_get_status(us, reply);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
@@ -208,7 +340,7 @@ static int usbat_check_status(struct us_data *us)
}
/*
- * Stores critical information in internal registers in prepartion for the execution
+ * Stores critical information in internal registers in preparation for the execution
* of a conditional usbat_read_blocks or usbat_write_blocks call.
*/
static int usbat_set_shuttle_features(struct us_data *us,
@@ -293,7 +425,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
return USB_STOR_TRANSPORT_FAILED;
if ((*status & 0x80)==0x00) { /* not busy */
- US_DEBUGP("Waited not busy for %d steps\n", i);
+ usb_stor_dbg(us, "Waited not busy for %d steps\n", i);
return USB_STOR_TRANSPORT_GOOD;
}
@@ -307,8 +439,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
msleep(1000); /* X minutes */
}
- US_DEBUGP("Waited not busy for %d minutes, timing out.\n",
- minutes);
+ usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n",
+ minutes);
return USB_STOR_TRANSPORT_FAILED;
}
@@ -316,8 +448,9 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
* Read block data from the data register
*/
static int usbat_read_block(struct us_data *us,
- unsigned char *content,
- unsigned short len)
+ void* buf,
+ unsigned short len,
+ int use_sg)
{
int result;
unsigned char *command = us->iobuf;
@@ -338,7 +471,7 @@ static int usbat_read_block(struct us_data *us,
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- result = usbat_bulk_read(us, content, len);
+ result = usbat_bulk_read(us, buf, len, use_sg);
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
}
@@ -348,9 +481,10 @@ static int usbat_read_block(struct us_data *us,
*/
static int usbat_write_block(struct us_data *us,
unsigned char access,
- unsigned char *content,
+ void* buf,
unsigned short len,
- int minutes)
+ int minutes,
+ int use_sg)
{
int result;
unsigned char *command = us->iobuf;
@@ -372,7 +506,7 @@ static int usbat_write_block(struct us_data *us,
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- result = usbat_bulk_write(us, content, len);
+ result = usbat_bulk_write(us, buf, len, use_sg);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -392,7 +526,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
unsigned char timeout,
unsigned char qualifier,
int direction,
- unsigned char *content,
+ void *buf,
unsigned short len,
int use_sg,
int minutes)
@@ -465,14 +599,14 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
data[1+(j<<1)] = data_out[j];
}
- result = usbat_bulk_write(us, data, num_registers*2);
+ result = usbat_bulk_write(us, data, num_registers*2, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
}
result = usb_stor_bulk_transfer_sg(us,
- pipe, content, len, use_sg, NULL);
+ pipe, buf, len, use_sg, NULL);
/*
* If we get a stall on the bulk download, we'll retry
@@ -523,8 +657,9 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
if (*status & 0x20) /* device fault */
return USB_STOR_TRANSPORT_FAILED;
- US_DEBUGP("Redoing %s\n",
- direction==DMA_TO_DEVICE ? "write" : "read");
+ usb_stor_dbg(us, "Redoing %s\n",
+ direction == DMA_TO_DEVICE
+ ? "write" : "read");
} else if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -533,8 +668,8 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
}
- US_DEBUGP("Bummer! %s bulk data 20 times failed.\n",
- direction==DMA_TO_DEVICE ? "Writing" : "Reading");
+ usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n",
+ direction == DMA_TO_DEVICE ? "Writing" : "Reading");
return USB_STOR_TRANSPORT_FAILED;
}
@@ -583,7 +718,7 @@ static int usbat_multiple_write(struct us_data *us,
}
/* Send the data */
- result = usbat_bulk_write(us, data, num_registers*2);
+ result = usbat_bulk_write(us, data, num_registers*2, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -606,8 +741,9 @@ static int usbat_multiple_write(struct us_data *us,
* other related details) are defined beforehand with _set_shuttle_features().
*/
static int usbat_read_blocks(struct us_data *us,
- unsigned char *buffer,
- int len)
+ void* buffer,
+ int len,
+ int use_sg)
{
int result;
unsigned char *command = us->iobuf;
@@ -627,7 +763,7 @@ static int usbat_read_blocks(struct us_data *us,
return USB_STOR_TRANSPORT_FAILED;
/* Read the blocks we just asked for */
- result = usbat_bulk_read(us, buffer, len);
+ result = usbat_bulk_read(us, buffer, len, use_sg);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
@@ -647,8 +783,9 @@ static int usbat_read_blocks(struct us_data *us,
* other related details) are defined beforehand with _set_shuttle_features().
*/
static int usbat_write_blocks(struct us_data *us,
- unsigned char *buffer,
- int len)
+ void* buffer,
+ int len,
+ int use_sg)
{
int result;
unsigned char *command = us->iobuf;
@@ -668,7 +805,7 @@ static int usbat_write_blocks(struct us_data *us,
return USB_STOR_TRANSPORT_FAILED;
/* Write the data */
- result = usbat_bulk_write(us, buffer, len);
+ result = usbat_bulk_write(us, buffer, len, use_sg);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
@@ -691,7 +828,7 @@ static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
data_flags,
USBAT_UIO_READ);
- US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags));
+ usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags);
return result;
}
@@ -764,10 +901,11 @@ static int usbat_device_enable_cdt(struct us_data *us)
/*
* Determine if media is present.
*/
-static int usbat_flash_check_media_present(unsigned char *uio)
+static int usbat_flash_check_media_present(struct us_data *us,
+ unsigned char *uio)
{
if (*uio & USBAT_UIO_UI0) {
- US_DEBUGP("usbat_flash_check_media_present: no media detected\n");
+ usb_stor_dbg(us, "no media detected\n");
return USBAT_FLASH_MEDIA_NONE;
}
@@ -777,10 +915,11 @@ static int usbat_flash_check_media_present(unsigned char *uio)
/*
* Determine if media has changed since last operation
*/
-static int usbat_flash_check_media_changed(unsigned char *uio)
+static int usbat_flash_check_media_changed(struct us_data *us,
+ unsigned char *uio)
{
if (*uio & USBAT_UIO_0) {
- US_DEBUGP("usbat_flash_check_media_changed: media change detected\n");
+ usb_stor_dbg(us, "media change detected\n");
return USBAT_FLASH_MEDIA_CHANGED;
}
@@ -801,7 +940,7 @@ static int usbat_flash_check_media(struct us_data *us,
return USB_STOR_TRANSPORT_ERROR;
/* Check for media existence */
- rc = usbat_flash_check_media_present(uio);
+ rc = usbat_flash_check_media_present(us, uio);
if (rc == USBAT_FLASH_MEDIA_NONE) {
info->sense_key = 0x02;
info->sense_asc = 0x3A;
@@ -810,7 +949,7 @@ static int usbat_flash_check_media(struct us_data *us,
}
/* Check for media change */
- rc = usbat_flash_check_media_changed(uio);
+ rc = usbat_flash_check_media_changed(us, uio);
if (rc == USBAT_FLASH_MEDIA_CHANGED) {
/* Reset and re-enable card detect */
@@ -853,7 +992,7 @@ static int usbat_identify_device(struct us_data *us,
rc = usbat_device_reset(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- msleep(25);
+ msleep(500);
/*
* In attempt to distinguish between HP CDRW's and Flash readers, we now
@@ -872,11 +1011,11 @@ static int usbat_identify_device(struct us_data *us,
/* Check for error bit, or if the command 'fell through' */
if (status == 0xA1 || !(status & 0x01)) {
/* Device is HP 8200 */
- US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
+ usb_stor_dbg(us, "Detected HP8200 CDRW\n");
info->devicetype = USBAT_DEV_HP8200;
} else {
/* Device is a CompactFlash reader/writer */
- US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+ usb_stor_dbg(us, "Detected Flash reader/writer\n");
info->devicetype = USBAT_DEV_FLASH;
}
@@ -887,22 +1026,28 @@ static int usbat_identify_device(struct us_data *us,
* Set the transport function based on the device type
*/
static int usbat_set_transport(struct us_data *us,
- struct usbat_info *info)
+ struct usbat_info *info,
+ int devicetype)
{
- int rc;
- if (!info->devicetype) {
- rc = usbat_identify_device(us, info);
- if (rc != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("usbat_set_transport: Could not identify device\n");
- return 1;
- }
- }
+ if (!info->devicetype)
+ info->devicetype = devicetype;
- if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+ if (!info->devicetype)
+ usbat_identify_device(us, info);
+
+ switch (info->devicetype) {
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+
+ case USBAT_DEV_HP8200:
us->transport = usbat_hp8200e_transport;
- else if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+ break;
+
+ case USBAT_DEV_FLASH:
us->transport = usbat_flash_transport;
+ break;
+ }
return 0;
}
@@ -933,7 +1078,7 @@ static int usbat_flash_get_sector_count(struct us_data *us,
/* ATA command : IDENTIFY DEVICE */
rc = usbat_multiple_write(us, registers, command, 3);
if (rc != USB_STOR_XFER_GOOD) {
- US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
+ usb_stor_dbg(us, "Gah! identify_device failed\n");
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -947,7 +1092,7 @@ static int usbat_flash_get_sector_count(struct us_data *us,
msleep(100);
/* Read the device identification data */
- rc = usbat_read_block(us, reply, 512);
+ rc = usbat_read_block(us, reply, 512, 0);
if (rc != USB_STOR_TRANSPORT_GOOD)
goto leave;
@@ -985,7 +1130,8 @@ static int usbat_flash_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
result = usbat_flash_check_media(us, info);
if (result != USB_STOR_TRANSPORT_GOOD)
@@ -1031,15 +1177,15 @@ static int usbat_flash_read_data(struct us_data *us,
goto leave;
/* Read the data we just requested */
- result = usbat_read_blocks(us, buffer, len);
+ result = usbat_read_blocks(us, buffer, len, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
goto leave;
- US_DEBUGP("usbat_flash_read_data: %d bytes\n", len);
+ usb_stor_dbg(us, "%d bytes\n", len);
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -1075,7 +1221,8 @@ static int usbat_flash_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
result = usbat_flash_check_media(us, info);
if (result != USB_STOR_TRANSPORT_GOOD)
@@ -1114,7 +1261,7 @@ static int usbat_flash_write_data(struct us_data *us,
/* Get the data from the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
/* ATA command 0x30 (WRITE SECTORS) */
usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30);
@@ -1125,7 +1272,7 @@ static int usbat_flash_write_data(struct us_data *us,
goto leave;
/* Write the data */
- result = usbat_write_blocks(us, buffer, len);
+ result = usbat_write_blocks(us, buffer, len, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
goto leave;
@@ -1154,21 +1301,20 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
unsigned char *buffer;
unsigned int len;
unsigned int sector;
- unsigned int sg_segment = 0;
unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
- US_DEBUGP("handle_read10: transfersize %d\n",
- srb->transfersize);
+ usb_stor_dbg(us, "transfersize %d\n", srb->transfersize);
- if (srb->request_bufflen < 0x10000) {
+ if (scsi_bufflen(srb) < 0x10000) {
result = usbat_hp8200e_rw_block_test(us, USBAT_ATA,
registers, data, 19,
USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
DMA_FROM_DEVICE,
- srb->request_buffer,
- srb->request_bufflen, srb->use_sg, 1);
+ scsi_sglist(srb),
+ scsi_bufflen(srb), scsi_sg_count(srb), 1);
return result;
}
@@ -1185,14 +1331,14 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
len = short_pack(data[7+9], data[7+8]);
len <<= 16;
len |= data[7+7];
- US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
- srb->transfersize = srb->request_bufflen/len;
+ usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len);
+ srb->transfersize = scsi_bufflen(srb)/len;
}
if (!srb->transfersize) {
srb->transfersize = 2048; /* A guess */
- US_DEBUGP("handle_read10: transfersize 0, forcing %d\n",
- srb->transfersize);
+ usb_stor_dbg(us, "transfersize 0, forcing %d\n",
+ srb->transfersize);
}
/*
@@ -1202,8 +1348,8 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
*/
len = (65535/srb->transfersize) * srb->transfersize;
- US_DEBUGP("Max read is %d bytes\n", len);
- len = min(len, srb->request_bufflen);
+ usb_stor_dbg(us, "Max read is %d bytes\n", len);
+ len = min(len, scsi_bufflen(srb));
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL) /* bloody hell! */
return USB_STOR_TRANSPORT_FAILED;
@@ -1212,13 +1358,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
sector |= short_pack(data[7+5], data[7+4]);
transferred = 0;
- sg_segment = 0; /* for keeping track of where we are in */
- sg_offset = 0; /* the scatter/gather list */
+ while (transferred != scsi_bufflen(srb)) {
- while (transferred != srb->request_bufflen) {
-
- if (len > srb->request_bufflen - transferred)
- len = srb->request_bufflen - transferred;
+ if (len > scsi_bufflen(srb) - transferred)
+ len = scsi_bufflen(srb) - transferred;
data[3] = len&0xFF; /* (cylL) = expected length (L) */
data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */
@@ -1247,14 +1390,14 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, srb,
- &sg_segment, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
/* Update the amount transferred and the sector number */
transferred += len;
sector += len / srb->transfersize;
- } /* while transferred != srb->request_bufflen */
+ } /* while transferred != scsi_bufflen(srb) */
kfree(buffer);
return result;
@@ -1310,7 +1453,7 @@ static int usbat_select_and_test_registers(struct us_data *us)
/*
* Initialize the USBAT processor and the storage device
*/
-int init_usbat(struct us_data *us)
+static int init_usbat(struct us_data *us, int devicetype)
{
int rc;
struct usbat_info *info;
@@ -1318,12 +1461,10 @@ int init_usbat(struct us_data *us)
unsigned char subcountL = USBAT_ATA_LBA_ME;
unsigned char *status = us->iobuf;
- us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+ us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
+ if (!us->extra)
return 1;
- }
- memset(us->extra, 0, sizeof(struct usbat_info));
+
info = (struct usbat_info *) (us->extra);
/* Enable peripheral control signals */
@@ -1333,7 +1474,7 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 1\n");
+ usb_stor_dbg(us, "INIT 1\n");
msleep(2000);
@@ -1341,7 +1482,7 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 2\n");
+ usb_stor_dbg(us, "INIT 2\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
@@ -1351,32 +1492,32 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 3\n");
+ usb_stor_dbg(us, "INIT 3\n");
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 4\n");
+ usb_stor_dbg(us, "INIT 4\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 5\n");
+ usb_stor_dbg(us, "INIT 5\n");
/* Enable peripheral control signals and card detect */
rc = usbat_device_enable_cdt(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 6\n");
+ usb_stor_dbg(us, "INIT 6\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 7\n");
+ usb_stor_dbg(us, "INIT 7\n");
msleep(1400);
@@ -1384,19 +1525,19 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 8\n");
+ usb_stor_dbg(us, "INIT 8\n");
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 9\n");
+ usb_stor_dbg(us, "INIT 9\n");
/* At this point, we need to detect which device we are using */
- if (usbat_set_transport(us, info))
+ if (usbat_set_transport(us, info, devicetype))
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 10\n");
+ usb_stor_dbg(us, "INIT 10\n");
if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {
subcountH = 0x02;
@@ -1407,7 +1548,7 @@ int init_usbat(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 11\n");
+ usb_stor_dbg(us, "INIT 11\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -1423,9 +1564,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned char data[32];
unsigned int len;
int i;
- char string[64];
- len = srb->request_bufflen;
+ len = scsi_bufflen(srb);
/* Send A0 (ATA PACKET COMMAND).
Note: I guess we're never going to get any of the ATA
@@ -1453,7 +1593,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
}
result = usbat_get_status(us, status);
- US_DEBUGP("Status = %02X\n", *status);
+ usb_stor_dbg(us, "Status = %02X\n", *status);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (srb->cmnd[0] == TEST_UNIT_READY)
@@ -1466,12 +1606,12 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
DMA_TO_DEVICE,
- srb->request_buffer,
- len, srb->use_sg, 10);
+ scsi_sglist(srb),
+ len, scsi_sg_count(srb), 10);
if (result == USB_STOR_TRANSPORT_GOOD) {
transferred += len;
- US_DEBUGP("Wrote %08X bytes\n", transferred);
+ usb_stor_dbg(us, "Wrote %08X bytes\n", transferred);
}
return result;
@@ -1484,15 +1624,15 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (len > 0xFFFF) {
- US_DEBUGP("Error: len = %08X... what do I do now?\n",
- len);
+ usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n",
+ len);
return USB_STOR_TRANSPORT_ERROR;
}
- if ( (result = usbat_multiple_write(us,
- registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
+ result = usbat_multiple_write(us, registers, data, 7);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- }
/*
* Write the 12-byte command header.
@@ -1504,12 +1644,11 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
* AT SPEED 4 IS UNRELIABLE!!!
*/
- if ( (result = usbat_write_block(us,
- USBAT_ATA, srb->cmnd, 12,
- srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
- USB_STOR_TRANSPORT_GOOD) {
+ result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12,
+ srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- }
/* If there is response data to be read in then do it here. */
@@ -1534,23 +1673,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
len = *status;
- result = usbat_read_block(us, srb->request_buffer, len);
-
- /* Debug-print the first 32 bytes of the transfer */
-
- if (!srb->use_sg) {
- string[0] = 0;
- for (i=0; i<len && i<32; i++) {
- sprintf(string+strlen(string), "%02X ",
- ((unsigned char *)srb->request_buffer)[i]);
- if ((i%16)==15) {
- US_DEBUGP("%s\n", string);
- string[0] = 0;
- }
- }
- if (string[0]!=0)
- US_DEBUGP("%s\n", string);
- }
+ result = usbat_read_block(us, scsi_sglist(srb), len,
+ scsi_sg_count(srb));
}
return result;
@@ -1570,7 +1694,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
};
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_response, sizeof(inquiry_response));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -1587,8 +1711,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
/* hard coded 512 byte sectors as per ATA spec */
info->ssize = 0x200;
- US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
/*
* build the reply
@@ -1603,7 +1727,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("usbat_flash_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1613,7 +1737,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("usbat_flash_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_read_data(us, info, block, blocks);
}
@@ -1627,7 +1752,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_read_data(us, info, block, blocks);
}
@@ -1637,7 +1763,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_write_data(us, info, block, blocks);
}
@@ -1651,13 +1778,14 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
rc = usbat_flash_check_media(us, info);
if (rc != USB_STOR_TRANSPORT_GOOD)
@@ -1667,7 +1795,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n");
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
memset(ptr, 0, 18);
ptr[0] = 0xF0;
@@ -1688,30 +1816,59 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
- US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
return USB_STOR_TRANSPORT_FAILED;
}
-/*
- * Default transport function. Attempts to detect which transport function
- * should be called, makes it the new default, and calls it.
- *
- * This function should never be called. Our usbat_init() function detects the
- * device type and changes the us->transport ptr to the transport function
- * relevant to the device.
- * However, we'll support this impossible(?) case anyway.
- */
-int usbat_transport(struct scsi_cmnd *srb, struct us_data *us)
+static int init_usbat_cd(struct us_data *us)
{
- struct usbat_info *info = (struct usbat_info*) (us->extra);
+ return init_usbat(us, USBAT_DEV_HP8200);
+}
- if (usbat_set_transport(us, info))
- return USB_STOR_TRANSPORT_ERROR;
+static int init_usbat_flash(struct us_data *us)
+{
+ return init_usbat(us, USBAT_DEV_FLASH);
+}
+
+static int usbat_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_data *us;
+ int result;
+
+ result = usb_stor_probe1(&us, intf, id,
+ (id - usbat_usb_ids) + usbat_unusual_dev_list);
+ if (result)
+ return result;
- return us->transport(srb, us);
+ /* The actual transport will be determined later by the
+ * initialization routine; this is just a placeholder.
+ */
+ us->transport_name = "Shuttle USBAT";
+ us->transport = usbat_flash_transport;
+ us->transport_reset = usb_stor_CB_reset;
+ us->max_lun = 0;
+
+ result = usb_stor_probe2(us);
+ return result;
}
+static struct usb_driver usbat_driver = {
+ .name = "ums-usbat",
+ .probe = usbat_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = usbat_usb_ids,
+ .soft_unbind = 1,
+ .no_dynamic_id = 1,
+};
+
+module_usb_driver(usbat_driver);
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
deleted file mode 100644
index 25e7d8b340b..00000000000
--- a/drivers/usb/storage/shuttle_usbat.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Driver for SCM Microsystems USB-ATAPI cable
- * Header File
- *
- * $Id: shuttle_usbat.h,v 1.5 2000/09/17 14:44:52 groovyjava Exp $
- *
- * Current development and maintenance by:
- * (c) 2000 Robert Baruch (autophile@dol.net)
- * (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
- *
- * See shuttle_usbat.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _USB_SHUTTLE_USBAT_H
-#define _USB_SHUTTLE_USBAT_H
-
-/* Supported device types */
-#define USBAT_DEV_HP8200 0x01
-#define USBAT_DEV_FLASH 0x02
-
-#define USBAT_EPP_PORT 0x10
-#define USBAT_EPP_REGISTER 0x30
-#define USBAT_ATA 0x40
-#define USBAT_ISA 0x50
-
-/* Commands (need to be logically OR'd with an access type */
-#define USBAT_CMD_READ_REG 0x00
-#define USBAT_CMD_WRITE_REG 0x01
-#define USBAT_CMD_READ_BLOCK 0x02
-#define USBAT_CMD_WRITE_BLOCK 0x03
-#define USBAT_CMD_COND_READ_BLOCK 0x04
-#define USBAT_CMD_COND_WRITE_BLOCK 0x05
-#define USBAT_CMD_WRITE_REGS 0x07
-
-/* Commands (these don't need an access type) */
-#define USBAT_CMD_EXEC_CMD 0x80
-#define USBAT_CMD_SET_FEAT 0x81
-#define USBAT_CMD_UIO 0x82
-
-/* Methods of accessing UIO register */
-#define USBAT_UIO_READ 1
-#define USBAT_UIO_WRITE 0
-
-/* Qualifier bits */
-#define USBAT_QUAL_FCQ 0x20 /* full compare */
-#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */
-
-/* USBAT Flash Media status types */
-#define USBAT_FLASH_MEDIA_NONE 0
-#define USBAT_FLASH_MEDIA_CF 1
-
-/* USBAT Flash Media change types */
-#define USBAT_FLASH_MEDIA_SAME 0
-#define USBAT_FLASH_MEDIA_CHANGED 1
-
-/* USBAT ATA registers */
-#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */
-#define USBAT_ATA_FEATURES 0x11 /* set features (W) */
-#define USBAT_ATA_ERROR 0x11 /* error (R) */
-#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */
-#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */
-#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */
-#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */
-#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */
-#define USBAT_ATA_STATUS 0x17 /* device status (R) */
-#define USBAT_ATA_CMD 0x17 /* device command (W) */
-#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */
-
-/* USBAT User I/O Data registers */
-#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */
-#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */
- /* CDT = ACKD & !UI1 & !UI0 */
-#define USBAT_UIO_1 0x20 /* I/O 1 */
-#define USBAT_UIO_0 0x10 /* I/O 0 */
-#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */
-#define USBAT_UIO_UI1 0x04 /* Input 1 */
-#define USBAT_UIO_UI0 0x02 /* Input 0 */
-#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
-
-/* USBAT User I/O Enable registers */
-#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */
-#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */
-#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */
- /* If ACKD=1, set OE1 to 1 also. */
-#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */
-#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */
-
-/* USBAT Features */
-#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */
-#define USBAT_FEAT_U1 0x08
-#define USBAT_FEAT_U0 0x04
-#define USBAT_FEAT_ET1 0x02
-#define USBAT_FEAT_ET2 0x01
-
-extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int init_usbat(struct us_data *us);
-
-struct usbat_info {
- int devicetype;
-
- /* Used for Flash readers only */
- unsigned long sectors; /* total sector count */
- unsigned long ssize; /* sector size in bytes */
-
- unsigned char sense_key;
- unsigned long sense_asc; /* additional sense code */
- unsigned long sense_ascq; /* additional sense code qualifier */
-};
-
-#endif
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
new file mode 100644
index 00000000000..2ea657be14c
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.c
@@ -0,0 +1,199 @@
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "sierra_ms.h"
+#include "debug.h"
+
+#define SWIMS_USB_REQUEST_SetSwocMode 0x0B
+#define SWIMS_USB_REQUEST_GetSwocInfo 0x0A
+#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_SET_MODE_Modem 0x0001
+
+#define TRU_NORMAL 0x01
+#define TRU_FORCE_MS 0x02
+#define TRU_FORCE_MODEM 0x03
+
+static unsigned int swi_tru_install = 1;
+module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def),"
+ " 2=Force CD-Rom, 3=Force Modem)");
+
+struct swoc_info {
+ __u8 rev;
+ __u8 reserved[8];
+ __u16 LinuxSKU;
+ __u16 LinuxVer;
+ __u8 reserved2[47];
+} __attribute__((__packed__));
+
+static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
+{
+ if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) ||
+ (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF))
+ return true;
+ else
+ return false;
+}
+
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
+{
+ int result;
+ dev_dbg(&udev->dev, "SWIMS: %s", "DEVICE MODE SWITCH\n");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */
+ USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */
+ eSWocMode, /* __u16 value */
+ 0x0000, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+
+static int sierra_get_swoc_info(struct usb_device *udev,
+ struct swoc_info *swocInfo)
+{
+ int result;
+
+ dev_dbg(&udev->dev, "SWIMS: Attempting to get TRU-Install info\n");
+
+ result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */
+ USB_TYPE_VENDOR | USB_DIR_IN, /* __u8 request type */
+ 0, /* __u16 value */
+ 0, /* __u16 index */
+ (void *) swocInfo, /* void *data */
+ sizeof(struct swoc_info), /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+
+ swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU);
+ swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer);
+ return result;
+}
+
+static void debug_swoc(const struct device *dev, struct swoc_info *swocInfo)
+{
+ dev_dbg(dev, "SWIMS: SWoC Rev: %02d\n", swocInfo->rev);
+ dev_dbg(dev, "SWIMS: Linux SKU: %04X\n", swocInfo->LinuxSKU);
+ dev_dbg(dev, "SWIMS: Linux Version: %04X\n", swocInfo->LinuxVer);
+}
+
+
+static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct swoc_info *swocInfo;
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int result;
+ if (swi_tru_install == TRU_FORCE_MS) {
+ result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
+ } else {
+ swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
+ if (!swocInfo) {
+ snprintf(buf, PAGE_SIZE, "Error\n");
+ return -ENOMEM;
+ }
+ result = sierra_get_swoc_info(udev, swocInfo);
+ if (result < 0) {
+ dev_dbg(dev, "SWIMS: failed SWoC query\n");
+ kfree(swocInfo);
+ snprintf(buf, PAGE_SIZE, "Error\n");
+ return -EIO;
+ }
+ debug_swoc(dev, swocInfo);
+ result = snprintf(buf, PAGE_SIZE,
+ "REV=%02d SKU=%04X VER=%04X\n",
+ swocInfo->rev,
+ swocInfo->LinuxSKU,
+ swocInfo->LinuxVer);
+ kfree(swocInfo);
+ }
+ return result;
+}
+static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL);
+
+int sierra_ms_init(struct us_data *us)
+{
+ int result, retries;
+ struct swoc_info *swocInfo;
+ struct usb_device *udev;
+ struct Scsi_Host *sh;
+
+ retries = 3;
+ result = 0;
+ udev = us->pusb_dev;
+
+ sh = us_to_host(us);
+ scsi_get_host_dev(sh);
+
+ /* Force Modem mode */
+ if (swi_tru_install == TRU_FORCE_MODEM) {
+ usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n");
+ result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+ if (result < 0)
+ usb_stor_dbg(us, "SWIMS: Failed to switch to modem mode\n");
+ return -EIO;
+ }
+ /* Force Mass Storage mode (keep CD-Rom) */
+ else if (swi_tru_install == TRU_FORCE_MS) {
+ usb_stor_dbg(us, "SWIMS: Forcing Mass Storage Mode\n");
+ goto complete;
+ }
+ /* Normal TRU-Install Logic */
+ else {
+ usb_stor_dbg(us, "SWIMS: Normal SWoC Logic\n");
+
+ swocInfo = kmalloc(sizeof(struct swoc_info),
+ GFP_KERNEL);
+ if (!swocInfo)
+ return -ENOMEM;
+
+ retries = 3;
+ do {
+ retries--;
+ result = sierra_get_swoc_info(udev, swocInfo);
+ if (result < 0) {
+ usb_stor_dbg(us, "SWIMS: Failed SWoC query\n");
+ schedule_timeout_uninterruptible(2*HZ);
+ }
+ } while (retries && result < 0);
+
+ if (result < 0) {
+ usb_stor_dbg(us, "SWIMS: Completely failed SWoC query\n");
+ kfree(swocInfo);
+ return -EIO;
+ }
+
+ debug_swoc(&us->pusb_dev->dev, swocInfo);
+
+ /* If there is not Linux software on the TRU-Install device
+ * then switch to modem mode
+ */
+ if (!containsFullLinuxPackage(swocInfo)) {
+ usb_stor_dbg(us, "SWIMS: Switching to Modem Mode\n");
+ result = sierra_set_ms_mode(udev,
+ SWIMS_SET_MODE_Modem);
+ if (result < 0)
+ usb_stor_dbg(us, "SWIMS: Failed to switch modem\n");
+ kfree(swocInfo);
+ return -EIO;
+ }
+ kfree(swocInfo);
+ }
+complete:
+ result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst);
+
+ return 0;
+}
+
diff --git a/drivers/usb/storage/sierra_ms.h b/drivers/usb/storage/sierra_ms.h
new file mode 100644
index 00000000000..bb48634ac1f
--- /dev/null
+++ b/drivers/usb/storage/sierra_ms.h
@@ -0,0 +1,4 @@
+#ifndef _SIERRA_MS_H_
+#define _SIERRA_MS_H_
+extern int sierra_ms_init(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 7ca896a342e..22c7d4360fa 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,7 +1,5 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.47 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -45,13 +43,15 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/sched.h>
+#include <linux/gfp.h>
#include <linux/errno.h>
-#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <linux/usb/quirks.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
@@ -60,6 +60,9 @@
#include "scsiglue.h"
#include "debug.h"
+#include <linux/blkdev.h>
+#include "../../scsi/sd.h"
+
/***********************************************************************
* Data transfer routines
@@ -76,14 +79,14 @@
* by a separate code path.)
*
* The abort function (usb_storage_command_abort() in scsiglue.c) first
- * sets the machine state and the ABORTING bit in us->flags to prevent
+ * sets the machine state and the ABORTING bit in us->dflags to prevent
* new URBs from being submitted. It then calls usb_stor_stop_transport()
- * below, which atomically tests-and-clears the URB_ACTIVE bit in us->flags
+ * below, which atomically tests-and-clears the URB_ACTIVE bit in us->dflags
* to see if the current_urb needs to be stopped. Likewise, the SG_ACTIVE
* bit is tested to see if the current_sg scatter-gather request needs to be
* stopped. The timeout callback routine does much the same thing.
*
- * When a disconnect occurs, the DISCONNECTING bit in us->flags is set to
+ * When a disconnect occurs, the DISCONNECTING bit in us->dflags is set to
* prevent new URBs from being submitted, and usb_stor_stop_transport() is
* called to stop any ongoing requests.
*
@@ -109,25 +112,12 @@
/* This is the completion handler which will wake us up when an URB
* completes.
*/
-static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs)
+static void usb_stor_blocking_completion(struct urb *urb)
{
- struct completion *urb_done_ptr = (struct completion *)urb->context;
+ struct completion *urb_done_ptr = urb->context;
complete(urb_done_ptr);
}
-
-/* This is the timeout handler which will cancel an URB when its timeout
- * expires.
- */
-static void timeout_handler(unsigned long us_)
-{
- struct us_data *us = (struct us_data *) us_;
-
- if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
- US_DEBUGP("Timeout -- cancelling URB\n");
- usb_unlink_urb(us->current_urb);
- }
-}
/* This is the common part of the URB message submission code
*
@@ -138,11 +128,11 @@ static void timeout_handler(unsigned long us_)
static int usb_stor_msg_common(struct us_data *us, int timeout)
{
struct completion urb_done;
- struct timer_list to_timer;
+ long timeleft;
int status;
- /* don't submit URBs during abort/disconnect processing */
- if (us->flags & ABORTING_OR_DISCONNECTING)
+ /* don't submit URBs during abort processing */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return -EIO;
/* set up data structures for the wakeup system */
@@ -150,19 +140,15 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
/* fill the common fields in the URB */
us->current_urb->context = &urb_done;
- us->current_urb->actual_length = 0;
- us->current_urb->error_count = 0;
- us->current_urb->status = 0;
+ us->current_urb->transfer_flags = 0;
/* we assume that if transfer_buffer isn't us->iobuf then it
* hasn't been mapped for DMA. Yes, this is clunky, but it's
* easier than always having the caller tell us whether the
* transfer buffer has already been mapped. */
- us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
if (us->current_urb->transfer_buffer == us->iobuf)
us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
us->current_urb->transfer_dma = us->iobuf_dma;
- us->current_urb->setup_dma = us->cr_dma;
/* submit the URB */
status = usb_submit_urb(us->current_urb, GFP_NOIO);
@@ -173,34 +159,29 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
/* since the URB has been submitted successfully, it's now okay
* to cancel it */
- set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+ set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
- /* did an abort/disconnect occur during the submission? */
- if (us->flags & ABORTING_OR_DISCONNECTING) {
+ /* did an abort occur during the submission? */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
/* cancel the URB, if it hasn't been cancelled already */
- if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
- US_DEBUGP("-- cancelling URB\n");
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+ usb_stor_dbg(us, "-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
}
- /* submit the timeout timer, if a timeout was requested */
- if (timeout > 0) {
- init_timer(&to_timer);
- to_timer.expires = jiffies + timeout;
- to_timer.function = timeout_handler;
- to_timer.data = (unsigned long) us;
- add_timer(&to_timer);
- }
-
/* wait for the completion of the URB */
- wait_for_completion(&urb_done);
- clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+ timeleft = wait_for_completion_interruptible_timeout(
+ &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
- /* clean up the timeout timer */
- if (timeout > 0)
- del_timer_sync(&to_timer);
+ clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+ if (timeleft <= 0) {
+ usb_stor_dbg(us, "%s -- cancelling URB\n",
+ timeleft == 0 ? "Timeout" : "Signal");
+ usb_kill_urb(us->current_urb);
+ }
/* return the URB status */
return us->current_urb->status;
@@ -216,9 +197,8 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
{
int status;
- US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __FUNCTION__, request, requesttype,
- value, index, size);
+ usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+ request, requesttype, value, index, size);
/* fill in the devrequest structure */
us->cr->bRequestType = requesttype;
@@ -238,6 +218,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
status = us->current_urb->actual_length;
return status;
}
+EXPORT_SYMBOL_GPL(usb_stor_control_msg);
/* This is a version of usb_clear_halt() that allows early termination and
* doesn't read the status from the device -- this is because some devices
@@ -264,14 +245,13 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
USB_ENDPOINT_HALT, endp,
NULL, 0, 3*HZ);
- /* reset the endpoint toggle */
if (result >= 0)
- usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
- usb_pipeout(pipe), 0);
+ usb_reset_endpoint(us->pusb_dev, endp);
- US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
+ usb_stor_dbg(us, "result = %d\n", result);
return result;
}
+EXPORT_SYMBOL_GPL(usb_stor_clear_halt);
/*
@@ -284,18 +264,18 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
static int interpret_urb_result(struct us_data *us, unsigned int pipe,
unsigned int length, int result, unsigned int partial)
{
- US_DEBUGP("Status code %d; transferred %u/%u\n",
- result, partial, length);
+ usb_stor_dbg(us, "Status code %d; transferred %u/%u\n",
+ result, partial, length);
switch (result) {
/* no error code; did we send all the data? */
case 0:
if (partial != length) {
- US_DEBUGP("-- short transfer\n");
+ usb_stor_dbg(us, "-- short transfer\n");
return USB_STOR_XFER_SHORT;
}
- US_DEBUGP("-- transfer complete\n");
+ usb_stor_dbg(us, "-- transfer complete\n");
return USB_STOR_XFER_GOOD;
/* stalled */
@@ -303,44 +283,40 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
/* for control endpoints, (used by CB[I]) a stall indicates
* a failed command */
if (usb_pipecontrol(pipe)) {
- US_DEBUGP("-- stall on control pipe\n");
+ usb_stor_dbg(us, "-- stall on control pipe\n");
return USB_STOR_XFER_STALLED;
}
/* for other sorts of endpoint, clear the stall */
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_stor_dbg(us, "clearing endpoint halt for pipe 0x%x\n",
+ pipe);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
- /* timeout or excessively long NAK */
- case -ETIMEDOUT:
- US_DEBUGP("-- timeout or NAK\n");
- return USB_STOR_XFER_ERROR;
-
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
- US_DEBUGP("-- babble\n");
+ usb_stor_dbg(us, "-- babble\n");
return USB_STOR_XFER_LONG;
/* the transfer was cancelled by abort, disconnect, or timeout */
case -ECONNRESET:
- US_DEBUGP("-- transfer cancelled\n");
+ usb_stor_dbg(us, "-- transfer cancelled\n");
return USB_STOR_XFER_ERROR;
/* short scatter-gather read transfer */
case -EREMOTEIO:
- US_DEBUGP("-- short read transfer\n");
+ usb_stor_dbg(us, "-- short read transfer\n");
return USB_STOR_XFER_SHORT;
/* abort or disconnect in progress */
case -EIO:
- US_DEBUGP("-- abort or disconnect in progress\n");
+ usb_stor_dbg(us, "-- abort or disconnect in progress\n");
return USB_STOR_XFER_ERROR;
/* the catch-all error case */
default:
- US_DEBUGP("-- unknown error\n");
+ usb_stor_dbg(us, "-- unknown error\n");
return USB_STOR_XFER_ERROR;
}
}
@@ -355,9 +331,8 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
{
int result;
- US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __FUNCTION__, request, requesttype,
- value, index, size);
+ usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+ request, requesttype, value, index, size);
/* fill in the devrequest structure */
us->cr->bRequestType = requesttype;
@@ -375,6 +350,7 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
return interpret_urb_result(us, pipe, size, result,
us->current_urb->actual_length);
}
+EXPORT_SYMBOL_GPL(usb_stor_ctrl_transfer);
/*
* Receive one interrupt buffer, without timeouts, but allowing early
@@ -390,7 +366,7 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf,
unsigned int pipe = us->recv_intr_pipe;
unsigned int maxp;
- US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+ usb_stor_dbg(us, "xfer %u bytes\n", length);
/* calculate the max packet size */
maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
@@ -417,7 +393,7 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
{
int result;
- US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+ usb_stor_dbg(us, "xfer %u bytes\n", length);
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
@@ -430,6 +406,7 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
return interpret_urb_result(us, pipe, length, result,
us->current_urb->actual_length);
}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
/*
* Transfer a scatter-gather list via bulk transfer
@@ -443,37 +420,36 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
{
int result;
- /* don't submit s-g requests during abort/disconnect processing */
- if (us->flags & ABORTING_OR_DISCONNECTING)
+ /* don't submit s-g requests during abort processing */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
- US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__,
- length, num_sg);
+ usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg);
result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
- sg, num_sg, length, SLAB_NOIO);
+ sg, num_sg, length, GFP_NOIO);
if (result) {
- US_DEBUGP("usb_sg_init returned %d\n", result);
+ usb_stor_dbg(us, "usb_sg_init returned %d\n", result);
return USB_STOR_XFER_ERROR;
}
/* since the block has been initialized successfully, it's now
* okay to cancel it */
- set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+ set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
- /* did an abort/disconnect occur during the submission? */
- if (us->flags & ABORTING_OR_DISCONNECTING) {
+ /* did an abort occur during the submission? */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
/* cancel the request, if it hasn't been cancelled already */
- if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
- US_DEBUGP("-- cancelling sg request\n");
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+ usb_stor_dbg(us, "-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
}
/* wait for the completion of the transfer */
usb_sg_wait(&us->current_sg);
- clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+ clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
result = us->current_sg.status;
if (act_len)
@@ -483,6 +459,23 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
}
/*
+ * Common used function. Transfer a complete command
+ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
+ */
+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+ struct scsi_cmnd* srb)
+{
+ unsigned int partial;
+ int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+ scsi_sg_count(srb), scsi_bufflen(srb),
+ &partial);
+
+ scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+ return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_srb);
+
+/*
* Transfer an entire SCSI command's worth of data payload over the bulk
* pipe.
*
@@ -516,11 +509,86 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
*residual = length_left;
return result;
}
+EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg);
/***********************************************************************
* Transport routines
***********************************************************************/
+/* There are so many devices that report the capacity incorrectly,
+ * this routine was written to counteract some of the resulting
+ * problems.
+ */
+static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct gendisk *disk;
+ struct scsi_disk *sdkp;
+ u32 sector;
+
+ /* To Report "Medium Error: Record Not Found */
+ static unsigned char record_not_found[18] = {
+ [0] = 0x70, /* current error */
+ [2] = MEDIUM_ERROR, /* = 0x03 */
+ [7] = 0x0a, /* additional length */
+ [12] = 0x14 /* Record Not Found */
+ };
+
+ /* If last-sector problems can't occur, whether because the
+ * capacity was already decremented or because the device is
+ * known to report the correct capacity, then we don't need
+ * to do anything.
+ */
+ if (!us->use_last_sector_hacks)
+ return;
+
+ /* Was this command a READ(10) or a WRITE(10)? */
+ if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10)
+ goto done;
+
+ /* Did this command access the last sector? */
+ sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) |
+ (srb->cmnd[4] << 8) | (srb->cmnd[5]);
+ disk = srb->request->rq_disk;
+ if (!disk)
+ goto done;
+ sdkp = scsi_disk(disk);
+ if (!sdkp)
+ goto done;
+ if (sector + 1 != sdkp->capacity)
+ goto done;
+
+ if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) {
+
+ /* The command succeeded. We know this device doesn't
+ * have the last-sector bug, so stop checking it.
+ */
+ us->use_last_sector_hacks = 0;
+
+ } else {
+ /* The command failed. Allow up to 3 retries in case this
+ * is some normal sort of failure. After that, assume the
+ * capacity is wrong and we're trying to access the sector
+ * beyond the end. Replace the result code and sense data
+ * with values that will cause the SCSI core to fail the
+ * command immediately, instead of going into an infinite
+ * (or even just a very long) retry loop.
+ */
+ if (++us->last_sector_retries < 3)
+ return;
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ memcpy(srb->sense_buffer, record_not_found,
+ sizeof(record_not_found));
+ }
+
+ done:
+ /* Don't reset the retry counter for TEST UNIT READY commands,
+ * because they get issued after device resets which might be
+ * caused by a failed last-sector access.
+ */
+ if (srb->cmnd[0] != TEST_UNIT_READY)
+ us->last_sector_retries = 0;
+}
+
/* Invoke the transport and basic error-handling/recovery methods
*
* This is used by the protocol layers to actually send the message to
@@ -532,21 +600,21 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
int result;
/* send the command to the transport layer */
- srb->resid = 0;
+ scsi_set_resid(srb, 0);
result = us->transport(srb, us);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
- US_DEBUGP("-- command was aborted\n");
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ usb_stor_dbg(us, "-- command was aborted\n");
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
- US_DEBUGP("-- transport indicates error, resetting\n");
+ usb_stor_dbg(us, "-- transport indicates error, resetting\n");
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
@@ -554,6 +622,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
+ last_sector_hacks(us, srb);
return;
}
@@ -572,9 +641,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* unless the operation involved a data-in transfer. Devices
* can signal most data-in errors by stalling the bulk-in pipe.
*/
- if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
+ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
srb->sc_data_direction != DMA_FROM_DEVICE) {
- US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ usb_stor_dbg(us, "-- CB transport device requiring auto-sense\n");
need_auto_sense = 1;
}
@@ -584,136 +653,211 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* "failure" and an "error" in the transport mechanism.
*/
if (result == USB_STOR_TRANSPORT_FAILED) {
- US_DEBUGP("-- transport indicates command failure\n");
+ usb_stor_dbg(us, "-- transport indicates command failure\n");
need_auto_sense = 1;
}
/*
+ * Determine if this device is SAT by seeing if the
+ * command executed successfully. Otherwise we'll have
+ * to wait for at least one CHECK_CONDITION to determine
+ * SANE_SENSE support
+ */
+ if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
+ result == USB_STOR_TRANSPORT_GOOD &&
+ !(us->fflags & US_FL_SANE_SENSE) &&
+ !(us->fflags & US_FL_BAD_SENSE) &&
+ !(srb->cmnd[2] & 0x20))) {
+ usb_stor_dbg(us, "-- SAT supported, increasing auto-sense\n");
+ us->fflags |= US_FL_SANE_SENSE;
+ }
+
+ /*
* A short transfer on a command where we don't expect it
* is unusual, but it doesn't mean we need to auto-sense.
*/
- if ((srb->resid > 0) &&
+ if ((scsi_get_resid(srb) > 0) &&
!((srb->cmnd[0] == REQUEST_SENSE) ||
(srb->cmnd[0] == INQUIRY) ||
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
- US_DEBUGP("-- unexpectedly short transfer\n");
+ usb_stor_dbg(us, "-- unexpectedly short transfer\n");
}
/* Now, if we need to do the auto-sense, let's do it */
if (need_auto_sense) {
int temp_result;
- void* old_request_buffer;
- unsigned short old_sg;
- unsigned old_request_bufflen;
- unsigned char old_sc_data_direction;
- unsigned char old_cmd_len;
- unsigned char old_cmnd[MAX_COMMAND_SIZE];
- int old_resid;
-
- US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
-
- /* save the old command */
- memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
- old_cmd_len = srb->cmd_len;
-
- /* set the command and the LUN */
- memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
- srb->cmnd[0] = REQUEST_SENSE;
- srb->cmnd[1] = old_cmnd[1] & 0xE0;
- srb->cmnd[4] = 18;
+ struct scsi_eh_save ses;
+ int sense_size = US_SENSE_SIZE;
+ struct scsi_sense_hdr sshdr;
+ const u8 *scdd;
+ u8 fm_ili;
+
+ /* device supports and needs bigger sense buffer */
+ if (us->fflags & US_FL_SANE_SENSE)
+ sense_size = ~0;
+Retry_Sense:
+ usb_stor_dbg(us, "Issuing auto-REQUEST_SENSE\n");
+
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
/* FIXME: we must do the protocol translation here */
- if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+ if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI ||
+ us->subclass == USB_SC_CYP_ATACB)
srb->cmd_len = 6;
else
srb->cmd_len = 12;
- /* set the transfer direction */
- old_sc_data_direction = srb->sc_data_direction;
- srb->sc_data_direction = DMA_FROM_DEVICE;
-
- /* use the new buffer we have */
- old_request_buffer = srb->request_buffer;
- srb->request_buffer = us->sensebuf;
-
- /* set the buffer length for transfer */
- old_request_bufflen = srb->request_bufflen;
- srb->request_bufflen = US_SENSE_SIZE;
-
- /* set up for no scatter-gather use */
- old_sg = srb->use_sg;
- srb->use_sg = 0;
-
/* issue the auto-sense command */
- old_resid = srb->resid;
- srb->resid = 0;
+ scsi_set_resid(srb, 0);
temp_result = us->transport(us->srb, us);
/* let's clean up right away */
- memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE);
- srb->resid = old_resid;
- srb->request_buffer = old_request_buffer;
- srb->request_bufflen = old_request_bufflen;
- srb->use_sg = old_sg;
- srb->sc_data_direction = old_sc_data_direction;
- srb->cmd_len = old_cmd_len;
- memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
-
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
- US_DEBUGP("-- auto-sense aborted\n");
+ scsi_eh_restore_cmnd(srb, &ses);
+
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ usb_stor_dbg(us, "-- auto-sense aborted\n");
srb->result = DID_ABORT << 16;
+
+ /* If SANE_SENSE caused this problem, disable it */
+ if (sense_size != US_SENSE_SIZE) {
+ us->fflags &= ~US_FL_SANE_SENSE;
+ us->fflags |= US_FL_BAD_SENSE;
+ }
goto Handle_Errors;
}
+
+ /* Some devices claim to support larger sense but fail when
+ * trying to request it. When a transport failure happens
+ * using US_FS_SANE_SENSE, we always retry with a standard
+ * (small) sense request. This fixes some USB GSM modems
+ */
+ if (temp_result == USB_STOR_TRANSPORT_FAILED &&
+ sense_size != US_SENSE_SIZE) {
+ usb_stor_dbg(us, "-- auto-sense failure, retry small sense\n");
+ sense_size = US_SENSE_SIZE;
+ us->fflags &= ~US_FL_SANE_SENSE;
+ us->fflags |= US_FL_BAD_SENSE;
+ goto Retry_Sense;
+ }
+
+ /* Other failures */
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("-- auto-sense failure\n");
+ usb_stor_dbg(us, "-- auto-sense failure\n");
/* we skip the reset if this happens to be a
* multi-target device, since failure of an
* auto-sense is perfectly valid
*/
srb->result = DID_ERROR << 16;
- if (!(us->flags & US_FL_SCM_MULT_TARG))
+ if (!(us->fflags & US_FL_SCM_MULT_TARG))
goto Handle_Errors;
return;
}
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- srb->sense_buffer[0],
- srb->sense_buffer[2] & 0xf,
- srb->sense_buffer[12],
- srb->sense_buffer[13]);
+ /* If the sense data returned is larger than 18-bytes then we
+ * assume this device supports requesting more in the future.
+ * The response code must be 70h through 73h inclusive.
+ */
+ if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) &&
+ !(us->fflags & US_FL_SANE_SENSE) &&
+ !(us->fflags & US_FL_BAD_SENSE) &&
+ (srb->sense_buffer[0] & 0x7C) == 0x70) {
+ usb_stor_dbg(us, "-- SANE_SENSE support enabled\n");
+ us->fflags |= US_FL_SANE_SENSE;
+
+ /* Indicate to the user that we truncated their sense
+ * because we didn't know it supported larger sense.
+ */
+ usb_stor_dbg(us, "-- Sense data truncated to %i from %i\n",
+ US_SENSE_SIZE,
+ srb->sense_buffer[7] + 8);
+ srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
+ }
+
+ scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+
+ usb_stor_dbg(us, "-- Result from auto-sense is %d\n",
+ temp_result);
+ usb_stor_dbg(us, "-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ sshdr.response_code, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
#ifdef CONFIG_USB_STORAGE_DEBUG
- usb_stor_show_sense(
- srb->sense_buffer[2] & 0xf,
- srb->sense_buffer[12],
- srb->sense_buffer[13]);
+ usb_stor_show_sense(us, sshdr.sense_key, sshdr.asc, sshdr.ascq);
#endif
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
- /* If things are really okay, then let's show that. Zero
- * out the sense buffer so the higher layers won't realize
- * we did an unsolicited auto-sense. */
- if (result == USB_STOR_TRANSPORT_GOOD &&
- /* Filemark 0, ignore EOM, ILI 0, no sense */
- (srb->sense_buffer[2] & 0xaf) == 0 &&
- /* No ASC or ASCQ */
- srb->sense_buffer[12] == 0 &&
- srb->sense_buffer[13] == 0) {
- srb->result = SAM_STAT_GOOD;
- srb->sense_buffer[0] = 0x0;
+ scdd = scsi_sense_desc_find(srb->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, 4);
+ fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0;
+
+ /* We often get empty sense data. This could indicate that
+ * everything worked or that there was an unspecified
+ * problem. We have to decide which.
+ */
+ if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 &&
+ fm_ili == 0) {
+ /* If things are really okay, then let's show that.
+ * Zero out the sense buffer so the higher layers
+ * won't realize we did an unsolicited auto-sense.
+ */
+ if (result == USB_STOR_TRANSPORT_GOOD) {
+ srb->result = SAM_STAT_GOOD;
+ srb->sense_buffer[0] = 0x0;
+
+ /* If there was a problem, report an unspecified
+ * hardware error to prevent the higher layers from
+ * entering an infinite retry loop.
+ */
+ } else {
+ srb->result = DID_ERROR << 16;
+ if ((sshdr.response_code & 0x72) == 0x72)
+ srb->sense_buffer[1] = HARDWARE_ERROR;
+ else
+ srb->sense_buffer[2] = HARDWARE_ERROR;
+ }
+ }
+ }
+
+ /*
+ * Some devices don't work or return incorrect data the first
+ * time they get a READ(10) command, or for the first READ(10)
+ * after a media change. If the INITIAL_READ10 flag is set,
+ * keep track of whether READ(10) commands succeed. If the
+ * previous one succeeded and this one failed, set the REDO_READ10
+ * flag to force a retry.
+ */
+ if (unlikely((us->fflags & US_FL_INITIAL_READ10) &&
+ srb->cmnd[0] == READ_10)) {
+ if (srb->result == SAM_STAT_GOOD) {
+ set_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+ } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) {
+ clear_bit(US_FLIDX_READ10_WORKED, &us->dflags);
+ set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+ }
+
+ /*
+ * Next, if the REDO_READ10 flag is set, return a result
+ * code that will cause the SCSI core to retry the READ(10)
+ * command immediately.
+ */
+ if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) {
+ clear_bit(US_FLIDX_REDO_READ10, &us->dflags);
+ srb->result = DID_IMM_RETRY << 16;
+ srb->sense_buffer[0] = 0;
}
}
/* Did we transfer less than the minimum amount required? */
- if (srb->result == SAM_STAT_GOOD &&
- srb->request_bufflen - srb->resid < srb->underflow)
- srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+ if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
+ scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
+ srb->result = DID_ERROR << 16;
+ last_sector_hacks(us, srb);
return;
/* Error and abort processing: try to resynchronize with the device
@@ -721,53 +865,55 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* device reset. */
Handle_Errors:
- /* Let the SCSI layer know we are doing a reset, set the
- * RESETTING bit, and clear the ABORTING bit so that the reset
- * may proceed. */
+ /* Set the RESETTING bit, and clear the ABORTING bit so that
+ * the reset may proceed. */
scsi_lock(us_to_host(us));
- usb_stor_report_bus_reset(us);
- set_bit(US_FLIDX_RESETTING, &us->flags);
- clear_bit(US_FLIDX_ABORTING, &us->flags);
+ set_bit(US_FLIDX_RESETTING, &us->dflags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
scsi_unlock(us_to_host(us));
+ /* We must release the device lock because the pre_reset routine
+ * will want to acquire it. */
+ mutex_unlock(&us->dev_mutex);
result = usb_stor_port_reset(us);
+ mutex_lock(&us->dev_mutex);
+
if (result < 0) {
scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us);
scsi_unlock(us_to_host(us));
us->transport_reset(us);
}
- clear_bit(US_FLIDX_RESETTING, &us->flags);
+ clear_bit(US_FLIDX_RESETTING, &us->dflags);
+ last_sector_hacks(us, srb);
}
/* Stop the current URB transfer */
void usb_stor_stop_transport(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
-
/* If the state machine is blocked waiting for an URB,
* let's wake it up. The test_and_clear_bit() call
* guarantees that if a URB has just been submitted,
* it won't be cancelled more than once. */
- if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
- US_DEBUGP("-- cancelling URB\n");
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+ usb_stor_dbg(us, "-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
/* If we are waiting for a scatter-gather operation, cancel it. */
- if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
- US_DEBUGP("-- cancelling sg request\n");
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+ usb_stor_dbg(us, "-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
}
/*
- * Control/Bulk/Interrupt transport
+ * Control/Bulk and Control/Bulk/Interrupt transport
*/
-int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
+int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- unsigned int transfer_length = srb->request_bufflen;
+ unsigned int transfer_length = scsi_bufflen(srb);
unsigned int pipe = 0;
int result;
@@ -779,7 +925,8 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
us->ifnum, srb->cmnd, srb->cmd_len);
/* check the return code for the command */
- US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
+ usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n",
+ result);
/* if we stalled the command, it means command failed */
if (result == USB_STOR_XFER_STALLED) {
@@ -796,10 +943,8 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
if (transfer_length) {
pipe = srb->sc_data_direction == DMA_FROM_DEVICE ?
us->recv_bulk_pipe : us->send_bulk_pipe;
- result = usb_stor_bulk_transfer_sg(us, pipe,
- srb->request_buffer, transfer_length,
- srb->use_sg, &srb->resid);
- US_DEBUGP("CBI data stage result is 0x%x\n", result);
+ result = usb_stor_bulk_srb(us, pipe, srb);
+ usb_stor_dbg(us, "CBI data stage result is 0x%x\n", result);
/* if we stalled the data transfer it means command failed */
if (result == USB_STOR_XFER_STALLED)
@@ -809,9 +954,16 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
}
/* STATUS STAGE */
+
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ if (us->protocol != USB_PR_CBI)
+ return USB_STOR_TRANSPORT_GOOD;
+
result = usb_stor_intr_transfer(us, us->iobuf, 2);
- US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
- us->iobuf[0], us->iobuf[1]);
+ usb_stor_dbg(us, "Got interrupt data (0x%x, 0x%x)\n",
+ us->iobuf[0], us->iobuf[1]);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -822,7 +974,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
* that this means we could be ignoring a real error on these
* commands, but that can't be helped.
*/
- if (us->subclass == US_SC_UFI) {
+ if (us->subclass == USB_SC_UFI) {
if (srb->cmnd[0] == REQUEST_SENSE ||
srb->cmnd[0] == INQUIRY)
return USB_STOR_TRANSPORT_GOOD;
@@ -838,8 +990,8 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
* into the first byte -- so if it's non-zero, call it a failure.
*/
if (us->iobuf[0]) {
- US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n",
- us->iobuf[0]);
+ usb_stor_dbg(us, "CBI IRQ data showed reserved bType 0x%x\n",
+ us->iobuf[0]);
goto Failed;
}
@@ -861,58 +1013,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
usb_stor_clear_halt(us, pipe);
return USB_STOR_TRANSPORT_FAILED;
}
-
-/*
- * Control/Bulk transport
- */
-int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
-{
- unsigned int transfer_length = srb->request_bufflen;
- int result;
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
- US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len);
-
- /* check the return code for the command */
- US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
-
- /* if we stalled the command, it means command failed */
- if (result == USB_STOR_XFER_STALLED) {
- return USB_STOR_TRANSPORT_FAILED;
- }
-
- /* Uh oh... serious problem here */
- if (result != USB_STOR_XFER_GOOD) {
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- if (transfer_length) {
- unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ?
- us->recv_bulk_pipe : us->send_bulk_pipe;
- result = usb_stor_bulk_transfer_sg(us, pipe,
- srb->request_buffer, transfer_length,
- srb->use_sg, &srb->resid);
- US_DEBUGP("CB data stage result is 0x%x\n", result);
-
- /* if we stalled the data transfer it means command failed */
- if (result == USB_STOR_XFER_STALLED)
- return USB_STOR_TRANSPORT_FAILED;
- if (result > USB_STOR_XFER_STALLED)
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* STATUS STAGE */
- /* NOTE: CB does not have a status stage. Silly, I know. So
- * we have to catch this at a higher level.
- */
- return USB_STOR_TRANSPORT_GOOD;
-}
+EXPORT_SYMBOL_GPL(usb_stor_CB_transport);
/*
* Bulk only transport
@@ -929,26 +1030,15 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
US_BULK_GET_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
- 0, us->ifnum, us->iobuf, 1, HZ);
+ 0, us->ifnum, us->iobuf, 1, 10*HZ);
- US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
- result, us->iobuf[0]);
+ usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+ result, us->iobuf[0]);
/* if we have a successful request, return the result */
if (result > 0)
return us->iobuf[0];
- /*
- * Some devices (i.e. Iomega Zip100) need this -- apparently
- * the bulk pipes get STALLed when the GetMaxLUN request is
- * processed. This is, in theory, harmless to all other devices
- * (regardless of if they stall or not).
- */
- if (result == -EPIPE) {
- usb_stor_clear_halt(us, us->recv_bulk_pipe);
- usb_stor_clear_halt(us, us->send_bulk_pipe);
- }
-
/*
* Some devices don't like GetMaxLUN. They may STALL the control
* pipe, they may return a zero-length result, they may do nothing at
@@ -963,7 +1053,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
- unsigned int transfer_length = srb->request_bufflen;
+ unsigned int transfer_length = scsi_bufflen(srb);
unsigned int residue;
int result;
int fake_sense = 0;
@@ -971,7 +1061,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
/* Take care of BULK32 devices; set extra byte to 0 */
- if ( unlikely(us->flags & US_FL_BULK32)) {
+ if (unlikely(us->fflags & US_FL_BULK32)) {
cbwlen = 32;
us->iobuf[31] = 0;
}
@@ -979,10 +1069,11 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
- bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+ bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
+ US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
- if (us->flags & US_FL_SCM_MULT_TARG)
+ if (us->fflags & US_FL_SCM_MULT_TARG)
bcb->Lun |= srb->device->id << 4;
bcb->Length = srb->cmd_len;
@@ -991,14 +1082,14 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
memcpy(bcb->CDB, srb->cmnd, bcb->Length);
/* send it to out endpoint */
- US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
- le32_to_cpu(bcb->Signature), bcb->Tag,
- le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
- (bcb->Lun >> 4), (bcb->Lun & 0x0F),
- bcb->Length);
+ usb_stor_dbg(us, "Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+ le32_to_cpu(bcb->Signature), bcb->Tag,
+ le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+ (bcb->Lun >> 4), (bcb->Lun & 0x0F),
+ bcb->Length);
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
bcb, cbwlen, NULL);
- US_DEBUGP("Bulk command transfer result=%d\n", result);
+ usb_stor_dbg(us, "Bulk command transfer result=%d\n", result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -1008,16 +1099,14 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Some USB-IDE converter chips need a 100us delay between the
* command phase and the data phase. Some devices need a little
* more than that, probably because of clock rate inaccuracies. */
- if (unlikely(us->flags & US_FL_GO_SLOW))
+ if (unlikely(us->fflags & US_FL_GO_SLOW))
udelay(125);
if (transfer_length) {
unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ?
us->recv_bulk_pipe : us->send_bulk_pipe;
- result = usb_stor_bulk_transfer_sg(us, pipe,
- srb->request_buffer, transfer_length,
- srb->use_sg, &srb->resid);
- US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+ result = usb_stor_bulk_srb(us, pipe, srb);
+ usb_stor_dbg(us, "Bulk data transfer result 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
@@ -1036,7 +1125,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
/* get CSW for device status */
- US_DEBUGP("Attempting to get CSW...\n");
+ usb_stor_dbg(us, "Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
@@ -1045,7 +1134,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
* CSWs. If we encounter such a thing, try to read the CSW again.
*/
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
- US_DEBUGP("Received 0-length CSW; retrying...\n");
+ usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
@@ -1054,23 +1143,24 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
- US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+ usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, NULL);
}
/* if we still have a failure at this point, we're in trouble */
- US_DEBUGP("Bulk status result = %d\n", result);
+ usb_stor_dbg(us, "Bulk status result = %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* check bulk status */
residue = le32_to_cpu(bcs->Residue);
- US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
- le32_to_cpu(bcs->Signature), bcs->Tag,
- residue, bcs->Status);
- if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) {
- US_DEBUGP("Bulk logical error\n");
+ usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+ le32_to_cpu(bcs->Signature), bcs->Tag,
+ residue, bcs->Status);
+ if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) ||
+ bcs->Status > US_BULK_STAT_PHASE) {
+ usb_stor_dbg(us, "Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1081,21 +1171,35 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
if (!us->bcs_signature) {
us->bcs_signature = bcs->Signature;
if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
- US_DEBUGP("Learnt BCS signature 0x%08X\n",
- le32_to_cpu(us->bcs_signature));
+ usb_stor_dbg(us, "Learnt BCS signature 0x%08X\n",
+ le32_to_cpu(us->bcs_signature));
} else if (bcs->Signature != us->bcs_signature) {
- US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
- le32_to_cpu(bcs->Signature),
- le32_to_cpu(us->bcs_signature));
+ usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature),
+ le32_to_cpu(us->bcs_signature));
return USB_STOR_TRANSPORT_ERROR;
}
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
- if (residue) {
- if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
+ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+
+ /* Heuristically detect devices that generate bogus residues
+ * by seeing what happens with INQUIRY and READ CAPACITY
+ * commands.
+ */
+ if (bcs->Status == US_BULK_STAT_OK &&
+ scsi_get_resid(srb) == 0 &&
+ ((srb->cmnd[0] == INQUIRY &&
+ transfer_length == 36) ||
+ (srb->cmnd[0] == READ_CAPACITY &&
+ transfer_length == 8))) {
+ us->fflags |= US_FL_IGNORE_RESIDUE;
+
+ } else {
residue = min(residue, transfer_length);
- srb->resid = max(srb->resid, (int) residue);
+ scsi_set_resid(srb, max(scsi_get_resid(srb),
+ (int) residue));
}
}
@@ -1127,6 +1231,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* we should never get here, but if we do, we're in trouble */
return USB_STOR_TRANSPORT_ERROR;
}
+EXPORT_SYMBOL_GPL(usb_stor_Bulk_transport);
/***********************************************************************
* Reset routines
@@ -1147,8 +1252,8 @@ static int usb_stor_reset_common(struct us_data *us,
int result;
int result2;
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- US_DEBUGP("No reset during disconnect\n");
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ usb_stor_dbg(us, "No reset during disconnect\n");
return -EIO;
}
@@ -1156,33 +1261,33 @@ static int usb_stor_reset_common(struct us_data *us,
request, requesttype, value, index, data, size,
5*HZ);
if (result < 0) {
- US_DEBUGP("Soft reset failed: %d\n", result);
+ usb_stor_dbg(us, "Soft reset failed: %d\n", result);
return result;
}
- /* Give the device some time to recover from the reset,
- * but don't delay disconnect processing. */
- wait_event_interruptible_timeout(us->delay_wait,
- test_bit(US_FLIDX_DISCONNECTING, &us->flags),
- HZ*6);
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- US_DEBUGP("Reset interrupted by disconnect\n");
+ /* Give the device some time to recover from the reset,
+ * but don't delay disconnect processing. */
+ wait_event_interruptible_timeout(us->delay_wait,
+ test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
+ HZ*6);
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ usb_stor_dbg(us, "Reset interrupted by disconnect\n");
return -EIO;
}
- US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
+ usb_stor_dbg(us, "Soft reset: clearing bulk-in endpoint halt\n");
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
- US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
+ usb_stor_dbg(us, "Soft reset: clearing bulk-out endpoint halt\n");
result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
/* return a result code based on the result of the clear-halts */
if (result >= 0)
result = result2;
if (result < 0)
- US_DEBUGP("Soft reset failed\n");
+ usb_stor_dbg(us, "Soft reset failed\n");
else
- US_DEBUGP("Soft reset done\n");
+ usb_stor_dbg(us, "Soft reset done\n");
return result;
}
@@ -1192,8 +1297,6 @@ static int usb_stor_reset_common(struct us_data *us,
int usb_stor_CB_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
-
memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
us->iobuf[0] = SEND_DIAGNOSTIC;
us->iobuf[1] = 4;
@@ -1201,44 +1304,45 @@ int usb_stor_CB_reset(struct us_data *us)
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE);
}
+EXPORT_SYMBOL_GPL(usb_stor_CB_reset);
/* This issues a Bulk-only Reset to the device in question, including
* clearing the subsequent endpoint halts that may occur.
*/
int usb_stor_Bulk_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __FUNCTION__);
-
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
}
+EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset);
-/* Issue a USB port reset to the device. But don't do anything if
- * there's more than one interface in the device, so that other users
- * are not affected. */
+/* Issue a USB port reset to the device. The caller must not hold
+ * us->dev_mutex.
+ */
int usb_stor_port_reset(struct us_data *us)
{
- int result, rc;
-
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- result = -EIO;
- US_DEBUGP("No reset during disconnect\n");
- } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
- result = -EBUSY;
- US_DEBUGP("Refusing to reset a multi-interface device\n");
- } else {
- result = rc =
- usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
- if (result < 0) {
- US_DEBUGP("unable to lock device for reset: %d\n",
- result);
+ int result;
+
+ /*for these devices we must use the class specific method */
+ if (us->pusb_dev->quirks & USB_QUIRK_RESET)
+ return -EPERM;
+
+ result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+ if (result < 0)
+ usb_stor_dbg(us, "unable to lock device for reset: %d\n",
+ result);
+ else {
+ /* Were we disconnected while waiting for the lock? */
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ result = -EIO;
+ usb_stor_dbg(us, "No reset during disconnect\n");
} else {
result = usb_reset_device(us->pusb_dev);
- if (rc)
- usb_unlock_device(us->pusb_dev);
- US_DEBUGP("usb_reset_device returns %d\n", result);
+ usb_stor_dbg(us, "usb_reset_device returns %d\n",
+ result);
}
+ usb_unlock_device(us->pusb_dev);
}
return result;
}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 0a362cc781a..9369d752d41 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Transport Functions Header File
*
- * $Id: transport.h,v 1.18 2002/04/21 02:57:59 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -41,78 +39,8 @@
#ifndef _TRANSPORT_H_
#define _TRANSPORT_H_
-#include <linux/config.h>
#include <linux/blkdev.h>
-/* 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 */
-#ifdef CONFIG_USB_STORAGE_USBAT
-#define US_PR_USBAT 0x80 /* SCM-ATAPI bridge */
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR09
-#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-#define US_PR_SDDR55 0x82 /* SDDR-55 (made up) */
-#endif
-#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
-#define US_PR_FREECOM 0xf1 /* Freecom */
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */
-#endif
-
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */
-#endif
-
-#define US_PR_DEVICE 0xff /* Use device's value */
-
-/*
- * Bulk only data structures
- */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
- __le32 Signature; /* contains 'USBC' */
- __u32 Tag; /* unique per command id */
- __le32 DataTransferLength; /* size of data */
- __u8 Flags; /* direction in bit 0 */
- __u8 Lun; /* LUN normally 0 */
- __u8 Length; /* of of the CDB */
- __u8 CDB[16]; /* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN 31
-#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
-#define US_BULK_FLAG_IN 1
-#define US_BULK_FLAG_OUT 0
-
-/* 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 */
- __u8 Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN 13
-#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
-#define US_BULK_STAT_OK 0
-#define US_BULK_STAT_FAIL 1
-#define US_BULK_STAT_PHASE 2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST 0xff
-#define US_BULK_GET_MAX_LUN 0xfe
-
/*
* usb_stor_bulk_transfer_xxx() return codes, in order of severity
*/
@@ -146,8 +74,6 @@ struct bulk_cs_wrap {
#define US_CBI_ADSC 0
-extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*);
-
extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
extern int usb_stor_CB_reset(struct us_data*);
@@ -170,6 +96,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len);
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+ struct scsi_cmnd* srb);
extern int usb_stor_port_reset(struct us_data *us);
#endif
diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h
new file mode 100644
index 00000000000..bb05b984d5f
--- /dev/null
+++ b/drivers/usb/storage/uas-detect.h
@@ -0,0 +1,96 @@
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include "usb.h"
+
+static int uas_is_interface(struct usb_host_interface *intf)
+{
+ return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
+ intf->desc.bInterfaceProtocol == USB_PR_UAS);
+}
+
+static int uas_isnt_supported(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ dev_warn(&udev->dev, "The driver for the USB controller %s does not "
+ "support scatter-gather which is\n",
+ hcd->driver->description);
+ dev_warn(&udev->dev, "required by the UAS driver. Please try an"
+ "alternative USB controller if you wish to use UAS.\n");
+ return -ENODEV;
+}
+
+static int uas_find_uas_alt_setting(struct usb_interface *intf)
+{
+ int i;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int sg_supported = udev->bus->sg_tablesize != 0;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ struct usb_host_interface *alt = &intf->altsetting[i];
+
+ if (uas_is_interface(alt)) {
+ if (!sg_supported)
+ return uas_isnt_supported(udev);
+ return alt->desc.bAlternateSetting;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int uas_find_endpoints(struct usb_host_interface *alt,
+ struct usb_host_endpoint *eps[])
+{
+ struct usb_host_endpoint *endpoint = alt->endpoint;
+ unsigned i, n_endpoints = alt->desc.bNumEndpoints;
+
+ for (i = 0; i < n_endpoints; i++) {
+ unsigned char *extra = endpoint[i].extra;
+ int len = endpoint[i].extralen;
+ while (len >= 3) {
+ 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];
+ }
+ }
+
+ if (!eps[0] || !eps[1] || !eps[2] || !eps[3])
+ return -ENODEV;
+
+ return 0;
+}
+
+static int uas_use_uas_driver(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_host_endpoint *eps[4] = { };
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ unsigned long flags = id->driver_info;
+ int r, alt;
+
+ usb_stor_adjust_quirks(udev, &flags);
+
+ if (flags & US_FL_IGNORE_UAS)
+ return 0;
+
+ if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams)
+ return 0;
+
+ alt = uas_find_uas_alt_setting(intf);
+ if (alt < 0)
+ return 0;
+
+ r = uas_find_endpoints(&intf->altsetting[alt], eps);
+ if (r < 0)
+ return 0;
+
+ return 1;
+}
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
new file mode 100644
index 00000000000..511b2295316
--- /dev/null
+++ b/drivers/usb/storage/uas.c
@@ -0,0 +1,1261 @@
+/*
+ * USB Attached SCSI
+ * Note that this is not the same as the USB Mass Storage driver
+ *
+ * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013
+ * 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/module.h>
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/storage.h>
+#include <linux/usb/uas.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.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>
+
+#include "uas-detect.h"
+
+/*
+ * 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];
+};
+
+struct uas_dev_info {
+ struct usb_interface *intf;
+ struct usb_device *udev;
+ struct usb_anchor cmd_urbs;
+ struct usb_anchor sense_urbs;
+ struct usb_anchor data_urbs;
+ int qdepth, resetting;
+ struct response_iu response;
+ unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
+ unsigned use_streams:1;
+ unsigned uas_sense_old:1;
+ unsigned running_task:1;
+ unsigned shutdown:1;
+ struct scsi_cmnd *cmnd;
+ spinlock_t lock;
+ struct work_struct work;
+ struct list_head inflight_list;
+ struct list_head dead_list;
+};
+
+enum {
+ SUBMIT_STATUS_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),
+ COMMAND_INFLIGHT = (1 << 8),
+ DATA_IN_URB_INFLIGHT = (1 << 9),
+ DATA_OUT_URB_INFLIGHT = (1 << 10),
+ COMMAND_COMPLETED = (1 << 11),
+ COMMAND_ABORTED = (1 << 12),
+ UNLINK_DATA_URBS = (1 << 13),
+ IS_IN_WORK_LIST = (1 << 14),
+};
+
+/* Overrides scsi_pointer */
+struct uas_cmd_info {
+ unsigned int state;
+ unsigned int stream;
+ struct urb *cmd_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 void uas_do_work(struct work_struct *work);
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
+static void uas_free_streams(struct uas_dev_info *devinfo);
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
+
+/* Must be called with devinfo->lock held, will temporary unlock the lock */
+static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
+ struct uas_cmd_info *cmdinfo,
+ unsigned long *lock_flags)
+{
+ /*
+ * The UNLINK_DATA_URBS flag makes sure uas_try_complete
+ * (called by urb completion) doesn't release cmdinfo
+ * underneath us.
+ */
+ cmdinfo->state |= UNLINK_DATA_URBS;
+ spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
+
+ if (cmdinfo->data_in_urb)
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ if (cmdinfo->data_out_urb)
+ usb_unlink_urb(cmdinfo->data_out_urb);
+
+ spin_lock_irqsave(&devinfo->lock, *lock_flags);
+ cmdinfo->state &= ~UNLINK_DATA_URBS;
+}
+
+static void uas_do_work(struct work_struct *work)
+{
+ struct uas_dev_info *devinfo =
+ container_of(work, struct uas_dev_info, work);
+ struct uas_cmd_info *cmdinfo;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+ SCp);
+
+ if (!(cmdinfo->state & IS_IN_WORK_LIST))
+ continue;
+
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+ if (!err)
+ cmdinfo->state &= ~IS_IN_WORK_LIST;
+ else
+ schedule_work(&devinfo->work);
+ }
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_mark_cmd_dead(struct uas_dev_info *devinfo,
+ struct uas_cmd_info *cmdinfo,
+ int result, const char *caller)
+{
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+
+ uas_log_cmd_state(cmnd, caller);
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
+ cmdinfo->state |= COMMAND_ABORTED;
+ cmdinfo->state &= ~IS_IN_WORK_LIST;
+ cmnd->result = result << 16;
+ list_move_tail(&cmdinfo->list, &devinfo->dead_list);
+}
+
+static void uas_abort_inflight(struct uas_dev_info *devinfo, int result,
+ const char *caller)
+{
+ struct uas_cmd_info *cmdinfo;
+ struct uas_cmd_info *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list, list)
+ uas_mark_cmd_dead(devinfo, cmdinfo, result, caller);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_add_work(struct uas_cmd_info *cmdinfo)
+{
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+ struct uas_dev_info *devinfo = cmnd->device->hostdata;
+
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ cmdinfo->state |= IS_IN_WORK_LIST;
+ schedule_work(&devinfo->work);
+}
+
+static void uas_zap_dead(struct uas_dev_info *devinfo)
+{
+ struct uas_cmd_info *cmdinfo;
+ struct uas_cmd_info *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, list) {
+ struct scsi_pointer *scp = (void *)cmdinfo;
+ struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+ SCp);
+ uas_log_cmd_state(cmnd, __func__);
+ WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
+ /* all urbs are killed, clear inflight bits */
+ cmdinfo->state &= ~(COMMAND_INFLIGHT |
+ DATA_IN_URB_INFLIGHT |
+ DATA_OUT_URB_INFLIGHT);
+ uas_try_complete(cmnd, __func__);
+ }
+ devinfo->running_task = 0;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+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;
+}
+
+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;
+}
+
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
+{
+ struct uas_cmd_info *ci = (void *)&cmnd->SCp;
+
+ scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ caller, cmnd, cmnd->request->tag,
+ (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
+ (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
+ (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "",
+ (ci->state & ALLOC_DATA_OUT_URB) ? " a-out" : "",
+ (ci->state & SUBMIT_DATA_OUT_URB) ? " s-out" : "",
+ (ci->state & ALLOC_CMD_URB) ? " a-cmd" : "",
+ (ci->state & SUBMIT_CMD_URB) ? " s-cmd" : "",
+ (ci->state & COMMAND_INFLIGHT) ? " CMD" : "",
+ (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "",
+ (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "",
+ (ci->state & COMMAND_COMPLETED) ? " done" : "",
+ (ci->state & COMMAND_ABORTED) ? " abort" : "",
+ (ci->state & UNLINK_DATA_URBS) ? " unlink": "",
+ (ci->state & IS_IN_WORK_LIST) ? " work" : "");
+}
+
+static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
+{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ if (cmdinfo->state & (COMMAND_INFLIGHT |
+ DATA_IN_URB_INFLIGHT |
+ DATA_OUT_URB_INFLIGHT |
+ UNLINK_DATA_URBS))
+ return -EBUSY;
+ WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
+ cmdinfo->state |= COMMAND_COMPLETED;
+ usb_free_urb(cmdinfo->data_in_urb);
+ usb_free_urb(cmdinfo->data_out_urb);
+ if (cmdinfo->state & COMMAND_ABORTED)
+ scmd_printk(KERN_INFO, cmnd, "abort completed\n");
+ list_del(&cmdinfo->list);
+ cmnd->scsi_done(cmnd);
+ return 0;
+}
+
+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_STATUS_URB;
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+ if (err) {
+ uas_add_work(cmdinfo);
+ }
+}
+
+static void uas_stat_cmplt(struct urb *urb)
+{
+ struct iu *iu = urb->transfer_buffer;
+ struct Scsi_Host *shost = urb->context;
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ struct scsi_cmnd *cmnd;
+ struct uas_cmd_info *cmdinfo;
+ unsigned long flags;
+ u16 tag;
+
+ if (urb->status) {
+ if (urb->status == -ENOENT) {
+ dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
+ urb->stream_id);
+ } else {
+ dev_err(&urb->dev->dev, "stat urb: status %d\n",
+ urb->status);
+ }
+ usb_free_urb(urb);
+ return;
+ }
+
+ if (devinfo->resetting) {
+ usb_free_urb(urb);
+ return;
+ }
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ tag = be16_to_cpup(&iu->tag) - 1;
+ if (tag == 0)
+ cmnd = devinfo->cmnd;
+ else
+ cmnd = scsi_host_find_tag(shost, tag - 1);
+
+ if (!cmnd) {
+ if (iu->iu_id == IU_ID_RESPONSE) {
+ if (!devinfo->running_task)
+ dev_warn(&urb->dev->dev,
+ "stat urb: recv unexpected response iu\n");
+ /* store results for uas_eh_task_mgmt() */
+ memcpy(&devinfo->response, iu, sizeof(devinfo->response));
+ }
+ usb_free_urb(urb);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return;
+ }
+
+ cmdinfo = (void *)&cmnd->SCp;
+ switch (iu->iu_id) {
+ case IU_ID_STATUS:
+ if (devinfo->cmnd == cmnd)
+ devinfo->cmnd = NULL;
+
+ 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);
+ if (cmnd->result != 0) {
+ /* cancel data transfers on error */
+ uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
+ }
+ cmdinfo->state &= ~COMMAND_INFLIGHT;
+ uas_try_complete(cmnd, __func__);
+ break;
+ case IU_ID_READ_READY:
+ if (!cmdinfo->data_in_urb ||
+ (cmdinfo->state & DATA_IN_URB_INFLIGHT)) {
+ scmd_printk(KERN_ERR, cmnd, "unexpected read rdy\n");
+ break;
+ }
+ uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
+ break;
+ case IU_ID_WRITE_READY:
+ if (!cmdinfo->data_out_urb ||
+ (cmdinfo->state & DATA_OUT_URB_INFLIGHT)) {
+ scmd_printk(KERN_ERR, cmnd, "unexpected write rdy\n");
+ break;
+ }
+ 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);
+ }
+ usb_free_urb(urb);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_data_cmplt(struct urb *urb)
+{
+ struct scsi_cmnd *cmnd = urb->context;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+ struct scsi_data_buffer *sdb = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ if (cmdinfo->data_in_urb == urb) {
+ sdb = scsi_in(cmnd);
+ cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
+ } else if (cmdinfo->data_out_urb == urb) {
+ sdb = scsi_out(cmnd);
+ cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
+ }
+ if (sdb == NULL) {
+ WARN_ON_ONCE(1);
+ } else if (urb->status) {
+ if (urb->status != -ECONNRESET) {
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd,
+ "data cmplt err %d stream %d\n",
+ urb->status, urb->stream_id);
+ }
+ /* error: no data transfered */
+ sdb->resid = sdb->length;
+ } else {
+ sdb->resid = sdb->length - urb->actual_length;
+ }
+ uas_try_complete(cmnd, __func__);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
+static void uas_cmd_cmplt(struct urb *urb)
+{
+ struct scsi_cmnd *cmnd = urb->context;
+
+ if (urb->status) {
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd, "cmd cmplt err %d\n", urb->status);
+ }
+ 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_cmnd *cmnd,
+ enum dma_data_direction dir)
+{
+ struct usb_device *udev = devinfo->udev;
+ struct urb *urb = usb_alloc_urb(0, gfp);
+ struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
+ ? scsi_in(cmnd) : scsi_out(cmnd);
+
+ if (!urb)
+ goto out;
+ usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
+ uas_data_cmplt, cmnd);
+ 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_Host *shost, 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 = kzalloc(sizeof(*iu), gfp);
+ if (!iu)
+ goto free;
+
+ usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
+ uas_stat_cmplt, shost);
+ 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)
+{
+ 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 = kzalloc(sizeof(*iu) + len, gfp);
+ if (!iu)
+ goto free;
+
+ iu->iu_id = IU_ID_COMMAND;
+ if (blk_rq_tagged(cmnd->request))
+ iu->tag = cpu_to_be16(cmnd->request->tag + 2);
+ else
+ iu->tag = cpu_to_be16(1);
+ 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,
+ uas_cmd_cmplt, cmnd);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+ out:
+ return urb;
+ free:
+ usb_free_urb(urb);
+ return NULL;
+}
+
+static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
+ u8 function, u16 stream_id)
+{
+ struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+ struct usb_device *udev = devinfo->udev;
+ struct urb *urb = usb_alloc_urb(0, gfp);
+ struct task_mgmt_iu *iu;
+ int err = -ENOMEM;
+
+ if (!urb)
+ goto err;
+
+ iu = kzalloc(sizeof(*iu), gfp);
+ if (!iu)
+ goto err;
+
+ iu->iu_id = IU_ID_TASK_MGMT;
+ iu->tag = cpu_to_be16(stream_id);
+ int_to_scsilun(cmnd->device->lun, &iu->lun);
+
+ iu->function = function;
+ switch (function) {
+ case TMF_ABORT_TASK:
+ if (blk_rq_tagged(cmnd->request))
+ iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
+ else
+ iu->task_tag = cpu_to_be16(1);
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
+ uas_cmd_cmplt, cmnd);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &devinfo->cmd_urbs);
+ err = usb_submit_urb(urb, gfp);
+ if (err) {
+ usb_unanchor_urb(urb);
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_ERR, cmnd, "task submission err %d\n", err);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ usb_free_urb(urb);
+ return err;
+}
+
+/*
+ * 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 struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd,
+ gfp_t gfp, unsigned int stream)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ struct urb *urb;
+ int err;
+
+ urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
+ if (!urb)
+ return NULL;
+ usb_anchor_urb(urb, &devinfo->sense_urbs);
+ err = usb_submit_urb(urb, gfp);
+ if (err) {
+ usb_unanchor_urb(urb);
+ uas_log_cmd_state(cmnd, __func__);
+ shost_printk(KERN_INFO, shost,
+ "sense urb submission error %d stream %d\n",
+ err, stream);
+ usb_free_urb(urb);
+ return NULL;
+ }
+ return urb;
+}
+
+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;
+ struct urb *urb;
+ int err;
+
+ WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
+ if (cmdinfo->state & SUBMIT_STATUS_URB) {
+ urb = uas_submit_sense_urb(cmnd, gfp, cmdinfo->stream);
+ if (!urb)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ cmdinfo->state &= ~SUBMIT_STATUS_URB;
+ }
+
+ if (cmdinfo->state & ALLOC_DATA_IN_URB) {
+ cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
+ devinfo->data_in_pipe, cmdinfo->stream,
+ 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) {
+ usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
+ err = usb_submit_urb(cmdinfo->data_in_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->data_in_urb);
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_INFO, cmnd,
+ "data in urb submission error %d stream %d\n",
+ err, cmdinfo->data_in_urb->stream_id);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+ cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
+ cmdinfo->state |= DATA_IN_URB_INFLIGHT;
+ }
+
+ if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
+ cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
+ devinfo->data_out_pipe, cmdinfo->stream,
+ 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) {
+ usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
+ err = usb_submit_urb(cmdinfo->data_out_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->data_out_urb);
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_INFO, cmnd,
+ "data out urb submission error %d stream %d\n",
+ err, cmdinfo->data_out_urb->stream_id);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+ cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
+ cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
+ }
+
+ if (cmdinfo->state & ALLOC_CMD_URB) {
+ cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
+ if (!cmdinfo->cmd_urb)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ cmdinfo->state &= ~ALLOC_CMD_URB;
+ }
+
+ if (cmdinfo->state & SUBMIT_CMD_URB) {
+ usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
+ err = usb_submit_urb(cmdinfo->cmd_urb, gfp);
+ if (err) {
+ usb_unanchor_urb(cmdinfo->cmd_urb);
+ uas_log_cmd_state(cmnd, __func__);
+ scmd_printk(KERN_INFO, cmnd,
+ "cmd urb submission error %d\n", err);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+ cmdinfo->cmd_urb = NULL;
+ cmdinfo->state &= ~SUBMIT_CMD_URB;
+ cmdinfo->state |= COMMAND_INFLIGHT;
+ }
+
+ return 0;
+}
+
+static int uas_queuecommand_lck(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;
+ unsigned long flags;
+ int err;
+
+ BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+
+ if (devinfo->resetting) {
+ cmnd->result = DID_ERROR << 16;
+ cmnd->scsi_done(cmnd);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return 0;
+ }
+
+ if (devinfo->cmnd) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
+ memset(cmdinfo, 0, sizeof(*cmdinfo));
+
+ if (blk_rq_tagged(cmnd->request)) {
+ cmdinfo->stream = cmnd->request->tag + 2;
+ } else {
+ devinfo->cmnd = cmnd;
+ cmdinfo->stream = 1;
+ }
+
+ cmnd->scsi_done = done;
+
+ cmdinfo->state = SUBMIT_STATUS_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_STATUS_URB) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+ uas_add_work(cmdinfo);
+ }
+
+ list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return 0;
+}
+
+static DEF_SCSI_QCMD(uas_queuecommand)
+
+static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
+ const char *fname, u8 function)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ u16 tag = devinfo->qdepth;
+ unsigned long flags;
+ struct urb *sense_urb;
+ int result = SUCCESS;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+
+ if (devinfo->resetting) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+
+ if (devinfo->running_task) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: error already running a task\n",
+ __func__, fname);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+
+ devinfo->running_task = 1;
+ memset(&devinfo->response, 0, sizeof(devinfo->response));
+ sense_urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC,
+ devinfo->use_streams ? tag : 0);
+ if (!sense_urb) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: submit sense urb failed\n",
+ __func__, fname);
+ devinfo->running_task = 0;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+ if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s: submit task mgmt urb failed\n",
+ __func__, fname);
+ devinfo->running_task = 0;
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ usb_kill_urb(sense_urb);
+ return FAILED;
+ }
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+
+ if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
+ /*
+ * Note we deliberately do not clear running_task here. If we
+ * allow new tasks to be submitted, there is no way to figure
+ * out if a received response_iu is for the failed task or for
+ * the new one. A bus-reset will eventually clear running_task.
+ */
+ shost_printk(KERN_INFO, shost,
+ "%s: %s timed out\n", __func__, fname);
+ return FAILED;
+ }
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+ devinfo->running_task = 0;
+ if (be16_to_cpu(devinfo->response.tag) != tag) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s failed (wrong tag %d/%d)\n", __func__,
+ fname, be16_to_cpu(devinfo->response.tag), tag);
+ result = FAILED;
+ } else if (devinfo->response.response_code != RC_TMF_COMPLETE) {
+ shost_printk(KERN_INFO, shost,
+ "%s: %s failed (rc 0x%x)\n", __func__,
+ fname, devinfo->response.response_code);
+ result = FAILED;
+ }
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+
+ return result;
+}
+
+static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
+{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+ struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+
+ if (devinfo->resetting) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ return FAILED;
+ }
+
+ uas_mark_cmd_dead(devinfo, cmdinfo, DID_ABORT, __func__);
+ if (cmdinfo->state & COMMAND_INFLIGHT) {
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
+ } else {
+ uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
+ uas_try_complete(cmnd, __func__);
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+ ret = SUCCESS;
+ }
+ return ret;
+}
+
+static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
+{
+ sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
+ return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
+ TMF_LOGICAL_UNIT_RESET);
+}
+
+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;
+ int err;
+
+ err = usb_lock_device_for_reset(udev, devinfo->intf);
+ if (err) {
+ shost_printk(KERN_ERR, sdev->host,
+ "%s FAILED to get lock err %d\n", __func__, err);
+ return FAILED;
+ }
+
+ shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
+ devinfo->resetting = 1;
+ uas_abort_inflight(devinfo, DID_RESET, __func__);
+ usb_kill_anchored_urbs(&devinfo->cmd_urbs);
+ usb_kill_anchored_urbs(&devinfo->sense_urbs);
+ usb_kill_anchored_urbs(&devinfo->data_urbs);
+ uas_zap_dead(devinfo);
+ err = usb_reset_device(udev);
+ devinfo->resetting = 0;
+
+ usb_unlock_device(udev);
+
+ if (err) {
+ shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
+ return FAILED;
+ }
+
+ shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
+ return SUCCESS;
+}
+
+static int uas_slave_alloc(struct scsi_device *sdev)
+{
+ sdev->hostdata = (void *)sdev->host->hostdata;
+
+ /* USB has unusual DMA-alignment requirements: Although the
+ * starting address of each scatter-gather element doesn't matter,
+ * the length of each element except the last must be divisible
+ * by the Bulk maxpacket value. There's currently no way to
+ * express this by block-layer constraints, so we'll cop out
+ * and simply require addresses to be aligned at 512-byte
+ * boundaries. This is okay since most block I/O involves
+ * hardware sectors that are multiples of 512 bytes in length,
+ * and since host controllers up through USB 2.0 have maxpacket
+ * values no larger than 512.
+ *
+ * But it doesn't suffice for Wireless USB, where Bulk maxpacket
+ * values can be as large as 2048. To make that work properly
+ * will require changes to the block layer.
+ */
+ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
+ 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 - 2);
+ 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_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,
+};
+
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+static struct usb_device_id uas_usb_ids[] = {
+# include "unusual_uas.h"
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
+ /* 0xaa is a prototype device I happen to have access to */
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, uas_usb_ids);
+
+#undef UNUSUAL_DEV
+
+static int uas_switch_interface(struct usb_device *udev,
+ struct usb_interface *intf)
+{
+ int alt;
+
+ alt = uas_find_uas_alt_setting(intf);
+ if (alt < 0)
+ return alt;
+
+ return usb_set_interface(udev,
+ intf->altsetting[0].desc.bInterfaceNumber, alt);
+}
+
+static int uas_configure_endpoints(struct uas_dev_info *devinfo)
+{
+ struct usb_host_endpoint *eps[4] = { };
+ struct usb_device *udev = devinfo->udev;
+ int r;
+
+ devinfo->uas_sense_old = 0;
+ devinfo->cmnd = NULL;
+
+ r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
+ if (r)
+ return r;
+
+ devinfo->cmd_pipe = usb_sndbulkpipe(udev,
+ usb_endpoint_num(&eps[0]->desc));
+ devinfo->status_pipe = usb_rcvbulkpipe(udev,
+ usb_endpoint_num(&eps[1]->desc));
+ devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
+ usb_endpoint_num(&eps[2]->desc));
+ devinfo->data_out_pipe = usb_sndbulkpipe(udev,
+ usb_endpoint_num(&eps[3]->desc));
+
+ if (udev->speed != USB_SPEED_SUPER) {
+ devinfo->qdepth = 256;
+ devinfo->use_streams = 0;
+ } else {
+ devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
+ 3, 256, GFP_NOIO);
+ if (devinfo->qdepth < 0)
+ return devinfo->qdepth;
+ devinfo->use_streams = 1;
+ }
+
+ return 0;
+}
+
+static void uas_free_streams(struct uas_dev_info *devinfo)
+{
+ struct usb_device *udev = devinfo->udev;
+ struct usb_host_endpoint *eps[3];
+
+ 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(devinfo->intf, eps, 3, GFP_NOIO);
+}
+
+static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int result = -ENOMEM;
+ struct Scsi_Host *shost = NULL;
+ struct uas_dev_info *devinfo;
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ if (!uas_use_uas_driver(intf, id))
+ return -ENODEV;
+
+ if (uas_switch_interface(udev, intf))
+ return -ENODEV;
+
+ shost = scsi_host_alloc(&uas_host_template,
+ sizeof(struct uas_dev_info));
+ if (!shost)
+ goto set_alt0;
+
+ shost->max_cmd_len = 16 + 252;
+ shost->max_id = 1;
+ shost->max_lun = 256;
+ shost->max_channel = 0;
+ shost->sg_tablesize = udev->bus->sg_tablesize;
+
+ devinfo = (struct uas_dev_info *)shost->hostdata;
+ devinfo->intf = intf;
+ devinfo->udev = udev;
+ devinfo->resetting = 0;
+ devinfo->running_task = 0;
+ devinfo->shutdown = 0;
+ init_usb_anchor(&devinfo->cmd_urbs);
+ init_usb_anchor(&devinfo->sense_urbs);
+ init_usb_anchor(&devinfo->data_urbs);
+ spin_lock_init(&devinfo->lock);
+ INIT_WORK(&devinfo->work, uas_do_work);
+ INIT_LIST_HEAD(&devinfo->inflight_list);
+ INIT_LIST_HEAD(&devinfo->dead_list);
+
+ result = uas_configure_endpoints(devinfo);
+ if (result)
+ goto set_alt0;
+
+ result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
+ if (result)
+ goto free_streams;
+
+ usb_set_intfdata(intf, shost);
+ result = scsi_add_host(shost, &intf->dev);
+ if (result)
+ goto free_streams;
+
+ scsi_scan_host(shost);
+ return result;
+
+free_streams:
+ uas_free_streams(devinfo);
+ usb_set_intfdata(intf, NULL);
+set_alt0:
+ usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
+ if (shost)
+ scsi_host_put(shost);
+ return result;
+}
+
+static int uas_pre_reset(struct usb_interface *intf)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (devinfo->shutdown)
+ return 0;
+
+ /* Block new requests */
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_block_requests(shost);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ /* Wait for any pending requests to complete */
+ flush_work(&devinfo->work);
+ if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
+ shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+ return 1;
+ }
+
+ uas_free_streams(devinfo);
+
+ return 0;
+}
+
+static int uas_post_reset(struct usb_interface *intf)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (devinfo->shutdown)
+ return 0;
+
+ if (uas_configure_endpoints(devinfo) != 0) {
+ shost_printk(KERN_ERR, shost,
+ "%s: alloc streams error after reset", __func__);
+ return 1;
+ }
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_report_bus_reset(shost, 0);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scsi_unblock_requests(shost);
+
+ return 0;
+}
+
+static int uas_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+ /* Wait for any pending requests to complete */
+ flush_work(&devinfo->work);
+ if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
+ shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+static int uas_resume(struct usb_interface *intf)
+{
+ return 0;
+}
+
+static int uas_reset_resume(struct usb_interface *intf)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+ unsigned long flags;
+
+ if (uas_configure_endpoints(devinfo) != 0) {
+ shost_printk(KERN_ERR, shost,
+ "%s: alloc streams error after reset", __func__);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ scsi_report_bus_reset(shost, 0);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ return 0;
+}
+
+static void uas_disconnect(struct usb_interface *intf)
+{
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+ devinfo->resetting = 1;
+ cancel_work_sync(&devinfo->work);
+ uas_abort_inflight(devinfo, DID_NO_CONNECT, __func__);
+ usb_kill_anchored_urbs(&devinfo->cmd_urbs);
+ usb_kill_anchored_urbs(&devinfo->sense_urbs);
+ usb_kill_anchored_urbs(&devinfo->data_urbs);
+ uas_zap_dead(devinfo);
+ scsi_remove_host(shost);
+ uas_free_streams(devinfo);
+ scsi_host_put(shost);
+}
+
+/*
+ * Put the device back in usb-storage mode on shutdown, as some BIOS-es
+ * hang on reboot when the device is still in uas mode. Note the reset is
+ * necessary as some devices won't revert to usb-storage mode without it.
+ */
+static void uas_shutdown(struct device *dev)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+
+ if (system_state != SYSTEM_RESTART)
+ return;
+
+ devinfo->shutdown = 1;
+ uas_free_streams(devinfo);
+ usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
+ usb_reset_device(udev);
+}
+
+static struct usb_driver uas_driver = {
+ .name = "uas",
+ .probe = uas_probe,
+ .disconnect = uas_disconnect,
+ .pre_reset = uas_pre_reset,
+ .post_reset = uas_post_reset,
+ .suspend = uas_suspend,
+ .resume = uas_resume,
+ .reset_resume = uas_reset_resume,
+ .drvwrap.driver.shutdown = uas_shutdown,
+ .id_table = uas_usb_ids,
+};
+
+module_usb_driver(uas_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(
+ "Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp");
diff --git a/drivers/usb/storage/freecom.h b/drivers/usb/storage/unusual_alauda.h
index 1b012d62d0a..fa3e9edaa2c 100644
--- a/drivers/usb/storage/freecom.h
+++ b/drivers/usb/storage/unusual_alauda.h
@@ -1,15 +1,4 @@
-/* Driver for Freecom USB/IDE adaptor
- *
- * $Id: freecom.h,v 1.4 2000/08/29 14:49:15 dlbrown Exp $
- *
- * Freecom v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 David Brown <usb-storage@davidb.org>
- *
- * See freecom.c for more explanation
+/* Unusual Devices File for the Alauda-based card readers
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,11 +15,17 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef _FREECOM_USB_H
-#define _FREECOM_USB_H
+#if defined(CONFIG_USB_STORAGE_ALAUDA) || \
+ defined(CONFIG_USB_STORAGE_ALAUDA_MODULE)
+
+UNUSUAL_DEV( 0x0584, 0x0008, 0x0102, 0x0102,
+ "Fujifilm",
+ "DPC-R1 (Alauda)",
+ USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0),
-extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int usb_stor_freecom_reset(struct us_data *us);
-extern int freecom_init (struct us_data *us);
+UNUSUAL_DEV( 0x07b4, 0x010a, 0x0102, 0x0102,
+ "Olympus",
+ "MAUSB-10 (Alauda)",
+ USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0),
-#endif
+#endif /* defined(CONFIG_USB_STORAGE_ALAUDA) || ... */
diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h
new file mode 100644
index 00000000000..82e8ed0324e
--- /dev/null
+++ b/drivers/usb/storage/unusual_cypress.h
@@ -0,0 +1,39 @@
+/* Unusual Devices File for devices based on the Cypress USB/ATA bridge
+ * with support for ATACB
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || \
+ defined(CONFIG_USB_STORAGE_CYPRESS_ATACB_MODULE)
+
+/* CY7C68300 : support atacb */
+UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
+ "Cypress",
+ "Cypress AT2LP",
+ USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+/* CY7C68310 : support atacb and atacb2 */
+UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999,
+ "Cypress",
+ "Cypress ISD-300LP",
+ USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160,
+ "Super Top",
+ "USB 2.0 SATA BRIDGE",
+ USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */
diff --git a/drivers/usb/storage/unusual_datafab.h b/drivers/usb/storage/unusual_datafab.h
new file mode 100644
index 00000000000..582a603c78b
--- /dev/null
+++ b/drivers/usb/storage/unusual_datafab.h
@@ -0,0 +1,98 @@
+/* Unusual Devices File for the Datafab USB Compact Flash reader
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_DATAFAB) || \
+ defined(CONFIG_USB_STORAGE_DATAFAB_MODULE)
+
+UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015,
+ "Datafab",
+ "MDCFE-B USB CF Reader",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+/*
+ * The following Datafab-based devices may or may not work
+ * using the current driver...the 0xffff is arbitrary since I
+ * don't know what device versions exist for these guys.
+ *
+ * The 0xa003 and 0xa004 devices in particular I'm curious about.
+ * I'm told they exist but so far nobody has come forward to say that
+ * they work with this driver. Given the success we've had getting
+ * other Datafab-based cards operational with this driver, I've decided
+ * to leave these two devices in the list.
+ */
+UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
+ "SIIG/Datafab",
+ "SIIG/Datafab Memory Stick+CF Reader/Writer",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+/* Reported by Josef Reisinger <josef.reisinger@netcologne.de> */
+UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff,
+ "Datafab/Unknown",
+ "MD2/MD3 Disk enclosure",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
+ "Datafab/Unknown",
+ "Datafab-based Reader",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
+ "Datafab/Unknown",
+ "Datafab-based Reader",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
+ "PNY/Datafab",
+ "PNY/Datafab CF+SM Reader",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
+ "Simple Tech/Datafab",
+ "Simple Tech/Datafab CF+SM Reader",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+/* Submitted by Olaf Hering <olh@suse.de> */
+UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
+ "Datafab Systems, Inc.",
+ "USB to CF + SM Combo (LC1)",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+/* Reported by Felix Moeller <felix@derklecks.de>
+ * in Germany this is sold by Hama with the productnumber 46952
+ * as "DualSlot CompactFlash(TM) & MStick Drive USB"
+ */
+UNUSUAL_DEV( 0x07c4, 0xa10b, 0x0000, 0xffff,
+ "DataFab Systems Inc.",
+ "USB CF+MS",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ 0),
+
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+ "Acomdata",
+ "CF",
+ USB_SC_SCSI, USB_PR_DATAFAB, NULL,
+ US_FL_SINGLE_LUN),
+
+#endif /* defined(CONFIG_USB_STORAGE_DATAFAB) || ... */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 9e926a8f211..80a5b366255 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Unusual Devices File
*
- * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -29,9 +27,9 @@
/* IMPORTANT NOTE: This file must be included in another file which does
* the following thing for it to work:
- * The macro UNUSUAL_DEV() must be defined before this file is included
+ * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined
+ * before this file is included.
*/
-#include <linux/config.h>
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
@@ -45,46 +43,63 @@
* running with this patch.
* Send your submission to either Phil Dibowitz <phil@ipom.com> or
* Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
- * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ * USB development list <linux-usb@vger.kernel.org> and the USB storage list
+ * <usb-storage@lists.one-eyed-alien.net>
+ */
+
+/* Note: If you add an entry only in order to set the CAPACITY_OK flag,
+ * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is
+ * because such entries mark devices which actually work correctly,
+ * as opposed to devices that do something strangely or wrongly.
*/
+/* In-kernel mode switching is deprecated. Do not add new devices to
+ * this list for the sole purpose of switching them to a different
+ * mode. Existing userspace solutions are superior.
+ *
+ * New mode switching devices should instead be added to the database
+ * maintained at http://www.draisberghof.de/usb_modeswitch/
+ */
+
+#if !defined(CONFIG_USB_STORAGE_SDDR09) && \
+ !defined(CONFIG_USB_STORAGE_SDDR09_MODULE)
+#define NO_SDDR09
+#endif
+
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
*/
UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
- "ATMEL",
- "SND1 Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE),
-
-UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
- "Mitsumi",
- "USB FDD",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
+ "ATMEL",
+ "SND1 Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
+/* Reported by Rodolfo Quesada <rquesada@roqz.net> */
+UNUSUAL_DEV( 0x03ee, 0x6906, 0x0003, 0x0003,
+ "VIA Technologies Inc.",
+ "Mitsumi multi cardreader",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
-UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
- US_SC_8070, US_PR_CB, NULL, 0),
+ USB_SC_8070, USB_PR_CB, NULL, 0),
-#ifdef CONFIG_USB_STORAGE_USBAT
-UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x03f0, 0x070c, 0x0000, 0x0000,
"HP",
- "CD-Writer+ 8200e",
- US_SC_8070, US_PR_USBAT, init_usbat, 0),
+ "Personal Media Drive",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
-UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
+/* Reported by Grant Grundler <grundler@parisc-linux.org>
+ * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
+ */
+UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001,
"HP",
- "CD-Writer+ CD-4e",
- US_SC_8070, US_PR_USBAT, init_usbat, 0),
-#endif
-
-/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
-UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
- "VIA Technologies Inc.",
- "USB 2.0 Card Reader",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE ),
+ "PhotoSmart R707",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
* and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
@@ -93,40 +108,169 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
UNUSUAL_DEV( 0x0409, 0x0040, 0x0000, 0x9999,
"NEC",
"NEC USB UF000x",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
-/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
+UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
+ "VIA Technologies Inc.",
+ "USB 2.0 Card Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Deduced by Jonathan Woithe <jwoithe@just42.net>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
*/
UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
"Buffalo",
"DUB-P40G HDD",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100,
+ "Samsung Info. Systems America, Inc.",
+ "MP3 Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Orgad Shaneh <orgads@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100,
+ "Samsung", "MP3 Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Christian Leber <christian@leber.de> */
+UNUSUAL_DEV( 0x0419, 0xaaf5, 0x0100, 0x0100,
+ "TrekStor",
+ "i.Beat 115 2.0",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_NOT_LOCKABLE ),
+
/* Reported by Stefan Werner <dustbln@gmx.de> */
UNUSUAL_DEV( 0x0419, 0xaaf6, 0x0100, 0x0100,
"TrekStor",
"i.Beat Joy 2.0",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
-UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
- "SMSC",
- "FDC GOLD-2.30",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
+/* Reported by Pete Zaitcev <zaitcev@redhat.com>, bz#176584 */
+UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100,
+ "GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
-#ifdef CONFIG_USB_STORAGE_DPCM
+/* Reported by Andrew Nayenko <relan@bk.ru>
+ * Updated for new firmware by Phillip Potter <phillipinda@hotmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0019, 0x0592, 0x0610,
+ "Nokia",
+ "Nokia 6288",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Mario Rettig <mariorettig@web.de> */
+UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
+ "Nokia",
+ "Nokia 3250",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by <honkkis@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100,
+ "Nokia",
+ "E70",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Jon Hart <Jon.Hart@web.de> */
+UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100,
+ "Nokia",
+ "E60",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and
+ * Einar Th. Einarsson <einarthered@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100,
+ "Nokia",
+ "N91",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Jiri Slaby <jirislaby@gmail.com> and
+ * Rene C. Castberg <Rene@Castberg.org> */
+UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100,
+ "Nokia",
+ "N80",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Matthew Bloch <matthew@bytemark.co.uk> */
+UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
+ "Nokia",
+ "E61",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Bardur Arantsson <bardur@scientician.net> */
+UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610,
+ "Nokia",
+ "6131",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Manuel Osdoba <manuel.osdoba@tu-ilmenau.de> */
+UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x9999,
+ "Nokia",
+ "Nokia 6233",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Alex Corcoles <alex@corcoles.net> */
+UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
+ "Nokia",
+ "6234",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Daniele Forsi <dforsi@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x04b9, 0x0350, 0x0350,
+ "Nokia",
+ "5300",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Patch submitted by Victor A. Santos <victoraur.santos@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x05af, 0x0742, 0x0742,
+ "Nokia",
+ "305",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
+/* Patch submitted by Mikhail Zolotaryov <lebon@lebon.org.ua> */
+UNUSUAL_DEV( 0x0421, 0x06aa, 0x1110, 0x1110,
+ "Nokia",
+ "502",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+#ifdef NO_SDDR09
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
- "CameraMate (DPCM_USB)",
- US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+ "CameraMate",
+ USB_SC_SCSI, USB_PR_CB, NULL,
+ US_FL_SINGLE_LUN ),
#endif
+/* Patch submitted by Daniel Drake <dsd@gentoo.org>
+ * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */
+UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100,
+ "Neuros Audio",
+ "USB 2.0 HD 2.5",
+ USB_SC_DEVICE, USB_PR_BULK, NULL,
+ US_FL_NEED_OVERRIDE ),
+
/*
* Pete Zaitcev <zaitcev@yahoo.com>, from Patrick C. F. Ernzer, bz#162559.
* The key does not actually break, but it returns zero sense which
@@ -135,57 +279,74 @@ UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100,
"USBest Technology", /* sold by Transcend */
"USB Mass Storage Device",
- US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
-/* Patch submitted by Daniel Drake <dsd@gentoo.org>
- * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */
-UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100,
- "Neuros Audio",
- "USB 2.0 HD 2.5",
- US_SC_DEVICE, US_PR_BULK, NULL,
- US_FL_NEED_OVERRIDE ),
+/*
+* Bohdan Linda <bohdan.linda@gmail.com>
+* 1GB USB sticks MyFlash High Speed. I have restricted
+* the revision to my model only
+*/
+UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100,
+ "USB 2.0",
+ "Flash Disk",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE ),
+
+/* Reported by Tamas Kerecsen <kerecsen@bigfoot.com>
+ * Obviously the PROM has not been customized by the VAR;
+ * the Vendor and Product string descriptors are:
+ * Generic Mass Storage (PROTOTYPE--Remember to change idVendor)
+ * Generic Manufacturer (PROTOTYPE--Remember to change idVendor)
+ */
+UNUSUAL_DEV( 0x045e, 0xffff, 0x0000, 0x0000,
+ "Mitac",
+ "GPS",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/*
+ * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.)
+ * Reported by Pete Zaitcev <zaitcev@redhat.com>
+ * This device chokes on both version of MODE SENSE which we have, so
+ * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT.
+ */
+UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100,
+ "AMI",
+ "Virtual Floppy",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT),
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
"Kyocera",
"Finecam S3x",
- US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+ USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0101, 0x0100, 0x0100,
"Kyocera",
"Finecam S4",
- US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+ USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
/* Patch submitted by Stephane Galles <stephane.galles@free.fr> */
UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100,
"Kyocera",
"Finecam S5",
- US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
-/* Patch for Kyocera Finecam L3
- * Submitted by Michael Krauth <michael.krauth@web.de>
- * and Alessandro Fracchetti <al.fracchetti@tin.it>
- */
-UNUSUAL_DEV( 0x0482, 0x0105, 0x0100, 0x0100,
+/* Patch submitted by Jens Taprogge <jens.taprogge@taprogge.org> */
+UNUSUAL_DEV( 0x0482, 0x0107, 0x0100, 0x0100,
"Kyocera",
- "Finecam L3",
- US_SC_SCSI, US_PR_BULK, NULL,
- US_FL_FIX_INQUIRY),
+ "CONTAX SL300R T*",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE),
/* Reported by Paul Stewart <stewart@wetlogic.net>
* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,
"Hitachi",
"DVD-CAM DZ-MV100A Camcorder",
- US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
-
-/* Reported by Andreas Bockhold <andreas@bockionline.de> */
-UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D70",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
+ USB_SC_SCSI, USB_PR_CB, NULL, US_FL_SINGLE_LUN),
/* BENQ DC5330
* Reported by Manuel Fombuena <mfombuena@ya.com> and
@@ -193,22 +354,37 @@ UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"300_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Patch for Nikon coolpix 2000
+ * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/
+UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
+ "NIKON",
+ "NIKON DSC E2000",
+ USB_SC_DEVICE, USB_PR_DEVICE,NULL,
+ US_FL_NOT_LOCKABLE ),
+
+/* Reported by Doug Maxey (dwm@austin.ibm.com) */
+UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110,
+ "IBM",
+ "IBM RSA2",
+ USB_SC_DEVICE, USB_PR_CB, NULL,
+ US_FL_MAX_SECTORS_MIN),
+
/* Reported by Simon Levitt <simon@whattf.com>
* This entry needs Sub and Proto fields */
UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100,
"Epson",
"875DC Storage",
- US_SC_SCSI, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+ USB_SC_SCSI, USB_PR_CB, NULL, US_FL_FIX_INQUIRY),
/* Reported by Khalid Aziz <khalid@gonehiking.org>
* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110,
"Epson",
"785EPX Storage",
- US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN),
+ USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_SINGLE_LUN),
/* Not sure who reported this originally but
* Pavel Machek <pavel@ucw.cz> reported that the extra US_FL_SINGLE_LUN
@@ -216,16 +392,16 @@ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110,
UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210,
"Fujifilm",
"FinePix 1400Zoom",
- US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
+ USB_SC_UFI, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
-/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
- * The device needs the flags only.
+/* Reported by Ondrej Zary <linux@rainbow-software.org>
+ * The device reports one sector more and breaks when that sector is accessed
*/
-UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074,
+UNUSUAL_DEV( 0x04ce, 0x0002, 0x026c, 0x026c,
"ScanLogic",
"SL11R-IDE",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
/* Reported by Kriston Fincher <kriston@airmail.net>
* Patch submitted by Sean Millichamp <sean@bruenor.org>
@@ -235,129 +411,134 @@ UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074,
UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200,
"Panasonic",
"LS-120 Camera",
- US_SC_UFI, US_PR_DEVICE, NULL, 0),
+ USB_SC_UFI, USB_PR_DEVICE, NULL, 0),
/* From Yukihiro Nakai, via zaitcev@yahoo.com.
* This is needed for CB instead of CBI */
UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000,
"Sharp CE-CW05",
"CD-R/RW Drive",
- US_SC_8070, US_PR_CB, NULL, 0),
+ USB_SC_8070, USB_PR_CB, NULL, 0),
/* Reported by Adriaan Penning <a.penning@luon.net> */
UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999,
"Panasonic",
"DMC-LCx Camera",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
/* Reported by Simeon Simeonov <simeonov_2000@yahoo.com> */
UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999,
"LEICA",
"D-LUX Camera",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
/* Most of the following entries were developed with the help of
* Shuttle/SCM directly.
*/
-UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
- US_SC_8020, US_PR_CB, NULL, 0),
+ USB_SC_8020, USB_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
- "Sandisk",
- "ImageMate SDDR09",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN ),
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+ US_FL_SCM_MULT_TARG ),
-/* This entry is from Andries.Brouwer@cwi.nl */
+#ifdef NO_SDDR09
UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
"SCM Microsystems",
- "eUSB SmartMedia / CompactFlash Adapter",
- US_SC_SCSI, US_PR_DPCM_USB, sddr09_init,
- 0),
+ "eUSB CompactFlash Adapter",
+ USB_SC_SCSI, USB_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
#endif
/* Reported by Markus Demleitner <msdemlei@cl.uni-heidelberg.de> */
-UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0100,
"SCM Microsystems Inc.",
"eUSB MMC Adapter",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN),
+ USB_SC_SCSI, USB_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
/* Reported by Daniel Nouri <dpunktnpunkt@web.de> */
-UNUSUAL_DEV( 0x04e6, 0x0006, 0x0205, 0x0205,
+UNUSUAL_DEV( 0x04e6, 0x0006, 0x0205, 0x0205,
"Shuttle",
"eUSB MMC Adapter",
- US_SC_SCSI, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN),
+ USB_SC_SCSI, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN),
-UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN),
+ USB_SC_SCSI, USB_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
-UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
- US_SC_8020, US_PR_CB, NULL, 0),
+ USB_SC_8020, USB_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
- US_SC_8020, US_PR_CB, NULL, 0),
+ USB_SC_8020, USB_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
+ USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
+ US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
- US_SC_8020, US_PR_CB, NULL, 0),
+ USB_SC_8020, USB_PR_CB, NULL, 0),
+
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
+ "Samsung",
+ "YP-U3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
+/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */
+UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999,
+ "Samsung",
+ "YP-CP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG),
+
+/* Added by Dmitry Artamonow <mad_soft@inbox.ru> */
+UNUSUAL_DEV( 0x04e8, 0x5136, 0x0000, 0x9999,
+ "Samsung",
+ "YP-Z3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Device uses standards-violating 32-byte Bulk Command Block Wrappers and
* reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
*/
-
UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100,
"Kobian Mercury",
"Binocam DCB-132",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BULK32),
-#ifdef CONFIG_USB_STORAGE_USBAT
-UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
- "Shuttle/SCM",
- "USBAT-02",
- US_SC_SCSI, US_PR_USBAT, init_usbat,
- US_FL_SINGLE_LUN),
-#endif
-
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
"Belkin",
"USB SCSI Adaptor",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
/* Iomega Clik! Drive
@@ -367,15 +548,22 @@ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
"Iomega",
"USB Clik! 40",
- US_SC_8070, US_PR_BULK, NULL,
+ USB_SC_8070, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Added by Alan Stern <stern@rowland.harvard.edu> */
+COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999,
+ "Linux",
+ "File-backed Storage Gadget",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_CAPACITY_OK ),
+
/* Yakumo Mega Image 37
* Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"300_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Another Yakumo camera.
@@ -383,14 +571,14 @@ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
UNUSUAL_DEV( 0x052b, 0x1804, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"300_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Reported by Iacopo Spalletti <avvisi@spalletti.it> */
UNUSUAL_DEV( 0x052b, 0x1807, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"300_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Yakumo Mega Image 47
@@ -398,7 +586,7 @@ UNUSUAL_DEV( 0x052b, 0x1807, 0x0100, 0x0100,
UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"400_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Reported by Paul Ortyl <ortylp@3miasto.net>
@@ -406,144 +594,159 @@ UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100,
UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100,
"Tekom Technologies, Inc",
"400_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
+UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
"Sony",
- "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
- US_SC_SCSI, US_PR_DEVICE, NULL,
+ "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
+ USB_SC_SCSI, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
-/* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500,
- "Sony",
- "DSC-T1",
- US_SC_8070, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
+/* Submitted by Lars Jacob <jacob.lars@googlemail.com>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610,
+ "Sony",
+ "DSC-T1/T5/H5",
+ USB_SC_8070, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
/* Reported by wim@geeks.nl */
-UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100,
"Sony",
"Memorystick NW-MS7",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
-#ifdef CONFIG_USB_STORAGE_ISD200
-UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110,
- "Sony",
- "Portable USB Harddrive V2",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
- 0 ),
-#endif
-
/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000,
"Sony",
"USB Floppy Drive",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
-UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Klaus Mueller <k.mueller@intershop.de> */
-UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310,
+UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310,
"Sony",
"Handycam",
- US_SC_SCSI, US_PR_DEVICE, NULL,
+ USB_SC_SCSI, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Rajesh Kumble Nayak <nayak@obs-nice.fr> */
-UNUSUAL_DEV( 0x054c, 0x002e, 0x0500, 0x0500,
+UNUSUAL_DEV( 0x054c, 0x002e, 0x0500, 0x0500,
"Sony",
"Handycam HC-85",
- US_SC_UFI, US_PR_DEVICE, NULL,
+ USB_SC_UFI, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999,
"Sony",
"Memorystick MSC-U01N",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Michal Mlotek <mlotek@foobar.pl> */
UNUSUAL_DEV( 0x054c, 0x0058, 0x0000, 0x9999,
"Sony",
"PEG N760c Memorystick",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999,
"Sony",
"Memorystick MSC-U03",
- US_SC_UFI, US_PR_CB, NULL,
+ USB_SC_UFI, USB_PR_CB, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Nathan Babb <nathan@lexi.com> */
UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999,
"Sony",
"PEG Mass Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY ),
+
+/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
+UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
+ "Sony",
+ "PEG Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* Submitted by Mike Alborn <malborn@deandra.homeip.net> */
UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
"Sony",
"PEG Mass Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
-
-/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
-UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
- "Sony",
- "PEG Mass Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
-
-UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
- "Y-E Data",
- "Flashbuster-U",
- US_SC_DEVICE, US_PR_CB, NULL,
- US_FL_SINGLE_LUN),
+/* Submitted by Ren Bigcren <bigcren.ren@sonymobile.com> */
+UNUSUAL_DEV( 0x054c, 0x02a5, 0x0100, 0x0100,
+ "Sony Corp.",
+ "MicroVault Flash Drive",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_READ_CAPACITY_16 ),
+
+/* floppy reports multiple luns */
+UNUSUAL_DEV( 0x055d, 0x2020, 0x0000, 0x0210,
+ "SAMSUNG",
+ "SFD-321U [FW 0C]",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
-UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
+/* We keep this entry to force the transport; firmware 3.00 and later is ok. */
+UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_CB, NULL,
US_FL_SINGLE_LUN),
/* Reported by Johann Cardon <johann.cardon@free.fr>
* This entry is needed only because the device reports
* bInterfaceClass = 0xff (vendor-specific)
*/
-UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999,
"Y-E Data",
"Silicon Media R/W",
- US_SC_DEVICE, US_PR_DEVICE, NULL, 0),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
+/* Reported by RTE <raszilki@yandex.ru> */
+UNUSUAL_DEV( 0x058f, 0x6387, 0x0141, 0x0141,
+ "JetFlash",
+ "TS1GJF2A/120",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
/* Fabrizio Fellini <fello@libero.it> */
UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Fujifilm",
"Digital Camera EX-20 DSC",
- US_SC_8070, US_PR_DEVICE, NULL, 0 ),
-
-/* The entry was here before I took over, and had US_SC_RBC. It turns
- * out that isn't needed. Additionally, Torsten Eriksson
- * <Torsten.Eriksson@bergianska.se> is able to use his device fine
- * without this entry at all - but I don't suspect that will be true
- * for all users (the protocol is likely needed), so is staying at
- * this time. - Phil Dibowitz <phil@ipom.com>
+ USB_SC_8070, USB_PR_DEVICE, NULL, 0 ),
+
+/* Reported by Andre Welter <a.r.welter@gmx.de>
+ * This antique device predates the release of the Bulk-only Transport
+ * spec, and if it gets a Get-Max-LUN then it requires the host to do a
+ * Clear-Halt on the bulk endpoints. The SINGLE_LUN flag will prevent
+ * us from sending the request.
*/
-UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x059b, 0x0001, 0x0100, 0x0100,
+ "Iomega",
+ "ZIP 100",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
+
+/* Reported by <Hendryk.Pfeiffer@gmx.de> */
+UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
"LaCie",
- "USB Hard Disk",
- US_SC_DEVICE, US_PR_CB, NULL, 0 ),
+ "DVD+-RW",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
/* Submitted by Joel Bourquard <numlock@freesurf.ch>
* Some versions of this device need the SubClass and Protocol overrides
@@ -552,35 +755,9 @@ UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110,
"In-System",
"PyroGate External CD-ROM Enclosure (FCD-523)",
- US_SC_SCSI, US_PR_BULK, NULL,
+ USB_SC_SCSI, USB_PR_BULK, NULL,
US_FL_NEED_OVERRIDE ),
-#ifdef CONFIG_USB_STORAGE_ISD200
-UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110,
- "In-System",
- "USB/IDE Bridge (ATA/ATAPI)",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
- 0 ),
-
-UNUSUAL_DEV( 0x05ab, 0x0301, 0x0100, 0x0110,
- "In-System",
- "Portable USB Harddrive V2",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
- 0 ),
-
-UNUSUAL_DEV( 0x05ab, 0x0351, 0x0100, 0x0110,
- "In-System",
- "Portable USB Harddrive V2",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
- 0 ),
-
-UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
- "In-System",
- "USB Storage Adapter V2",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
- 0 ),
-#endif
-
/* Submitted by Sven Anderson <sven-linux@anderson.de>
* There are at least four ProductIDs used for iPods, so I added 0x1202 and
* 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears
@@ -590,26 +767,26 @@ UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
UNUSUAL_DEV( 0x05ac, 0x1202, 0x0000, 0x9999,
"Apple",
"iPod",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
/* Reported by Avi Kivity <avi@argo.co.il> */
UNUSUAL_DEV( 0x05ac, 0x1203, 0x0000, 0x9999,
"Apple",
"iPod",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999,
"Apple",
"iPod",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999,
"Apple",
"iPod",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
/*
@@ -619,22 +796,26 @@ UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999,
UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999,
"Apple",
"iPod",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
- "Lexar",
- "Jumpshot USB CF Reader",
- US_SC_SCSI, US_PR_JUMPSHOT, NULL,
- US_FL_NEED_OVERRIDE ),
-#endif
+/* Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* Globetrotter HSDPA; mass storage shows up as Qualcomm for vendor */
+UNUSUAL_DEV( 0x05c6, 0x1000, 0x0000, 0x9999,
+ "Option N.V.",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
+ 0),
/* Reported by Blake Matheny <bmatheny@purdue.edu> */
UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113,
"Lexar",
"USB CF Reader",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* The following two entries are for a Genesys USB to IDE
@@ -643,239 +824,191 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113,
* They were originally reported by Alexander Oltu
* <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
* respectively.
+ *
+ * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz
+ * <phil@ipom.com> as these flags were made and hard-coded
+ * special-cases were pulled from scsiglue.c.
*/
UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Optical",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,
+ "Genesys Logic",
+ "USB to SATA",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
/* Reported by Hanno Boeck <hanno@gmx.de>
* Taken from the Lycoris Kernel */
UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999,
"Vivitar",
"Vivicam 35Xx",
- US_SC_SCSI, US_PR_BULK, NULL,
+ USB_SC_SCSI, USB_PR_BULK, NULL,
US_FL_FIX_INQUIRY ),
-UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
- US_SC_UFI, US_PR_CB, NULL, 0 ),
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
- "Olympus",
- "Camedia MAUSB-2",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN ),
-#endif
+ USB_SC_UFI, USB_PR_CB, NULL, 0 ),
/* Reported by Darsen Lu <darsen@micro.ee.nthu.edu.tw> */
UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
"SigmaTel",
"USBMSC Audio Player",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Daniel Kukula <daniel.kuku@gmail.com> */
+UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100,
+ "Prolific Technology, Inc.",
+ "Prolific Storage Gadget",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BAD_SENSE ),
+
+/* Reported by Rogerio Brito <rbrito@ime.usp.br> */
+UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001,
+ "Prolific Technology, Inc.",
+ "Mass Storage Device",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE ),
+
/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
-UNUSUAL_DEV( 0x067b, 0x2507, 0x0100, 0x0100,
+/* Change to bcdDeviceMin (0x0100 to 0x0001) reported by
+ * Thomas Bartosik <tbartdev@gmx-topmail.de> */
+UNUSUAL_DEV( 0x067b, 0x2507, 0x0001, 0x0100,
"Prolific Technology Inc.",
"Mass Storage Device",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
-UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0101,
"Prolific Technology Inc.",
"ATAPI-6 Bridge Controller",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
/* Submitted by Benny Sjostrand <benny@hostmobility.com> */
UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
"Minolta",
"Dimage F300",
- US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+ USB_SC_SCSI, USB_PR_BULK, NULL, 0 ),
/* Reported by Miguel A. Fosas <amn3s1a@ono.com> */
UNUSUAL_DEV( 0x0686, 0x4017, 0x0001, 0x0001,
- "Minolta",
- "DIMAGE E223",
- US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
-
-UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100,
- "Hagiwara",
- "FlashGate SmartMedia",
- US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+ "Minolta",
+ "DIMAGE E223",
+ USB_SC_SCSI, USB_PR_DEVICE, NULL, 0 ),
UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
- US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+ USB_SC_SCSI, USB_PR_BULK, NULL, 0 ),
+
+/* Reported by David Hamilton <niftimusmaximus@lycos.com> */
+UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001,
+ "Thomson Multimedia Inc.",
+ "RCA RD1080 MP3 Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
-UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
+/* Reported by Adrian Pilchowiec <adi1981@epf.pl> */
+UNUSUAL_DEV( 0x071b, 0x3203, 0x0000, 0x0000,
+ "RockChip",
+ "MP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64 |
+ US_FL_NO_READ_CAPACITY_16),
+
+/* Reported by Jean-Baptiste Onofre <jb@nanthrax.net>
+ * Support the following product :
+ * "Dane-Elec MediaTouch"
+ */
+UNUSUAL_DEV( 0x071b, 0x32bb, 0x0000, 0x0000,
+ "RockChip",
+ "MTP",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64),
+
+/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
+ * This USB MP3/AVI player device fails and disconnects if more than 128
+ * sectors (64kB) are read/written in a single command, and may be present
+ * at least in the following products:
+ * "Magnex Digital Video Panel DVP 1800"
+ * "MP4 AIGO 4GB SLOT SD"
+ * "Teclast TL-C260 MP3"
+ * "i.Meizu PMP MP3/MP4"
+ * "Speed MV8 MP4 Audio Player"
+ */
+UNUSUAL_DEV( 0x071b, 0x3203, 0x0100, 0x0100,
+ "RockChip",
+ "ROCK MP3",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
+/* Reported by Olivier Blondeau <zeitoun@gmail.com> */
+UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100,
+ "ATMEL",
+ "SND1 Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
+/* Submitted by Roman Hodek <roman@hodek.net> */
+UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
"ImageMate SDDR-05a",
- US_SC_SCSI, US_PR_CB, NULL,
+ USB_SC_SCSI, USB_PR_CB, NULL,
US_FL_SINGLE_LUN ),
-#ifdef CONFIG_USB_STORAGE_USBAT
-UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005,
- "Sandisk",
- "ImageMate SDDR-05b",
- US_SC_SCSI, US_PR_USBAT, init_usbat,
- US_FL_SINGLE_LUN ),
-#endif
+UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009,
+ "SanDisk Corporation",
+ "ImageMate CompactFlash USB",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
- US_SC_SCSI, US_PR_CB, NULL,
+ USB_SC_SCSI, USB_PR_CB, NULL,
US_FL_SINGLE_LUN ),
-#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999,
- "Sandisk",
- "ImageMate SDDR-09",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN ),
-#endif
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
-UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
- "Freecom",
- "USB-IDE",
- US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
-#endif
-
/* Reported by Eero Volotinen <eero@ping-viini.org> */
UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999,
"Freecom Technologies",
"FHD-Classic",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
-UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
+UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
"Microtech",
"USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
- US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+ US_FL_SCM_MULT_TARG ),
-#ifdef CONFIG_USB_STORAGE_DPCM
+#ifdef NO_SDDR09
UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
- "CameraMate (DPCM_USB)",
- US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015,
- "Datafab",
- "MDCFE-B USB CF Reader",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-/*
- * The following Datafab-based devices may or may not work
- * using the current driver...the 0xffff is arbitrary since I
- * don't know what device versions exist for these guys.
- *
- * The 0xa003 and 0xa004 devices in particular I'm curious about.
- * I'm told they exist but so far nobody has come forward to say that
- * they work with this driver. Given the success we've had getting
- * other Datafab-based cards operational with this driver, I've decided
- * to leave these two devices in the list.
- */
-UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
- "SIIG/Datafab",
- "SIIG/Datafab Memory Stick+CF Reader/Writer",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-/* Reported by Josef Reisinger <josef.reisinger@netcologne.de> */
-UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff,
- "Datafab/Unknown",
- "MD2/MD3 Disk enclosure",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- US_FL_SINGLE_LUN ),
-
-UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
- "Datafab/Unknown",
- "Datafab-based Reader",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
- "Datafab/Unknown",
- "Datafab-based Reader",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
- "PNY/Datafab",
- "PNY/Datafab CF+SM Reader",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
- "Simple Tech/Datafab",
- "Simple Tech/Datafab CF+SM Reader",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-#endif
-
-#ifdef CONFIG_USB_STORAGE_SDDR55
-/* Contributed by Peter Waechtler */
-UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999,
- "Datafab",
- "MDSM-B reader",
- US_SC_SCSI, US_PR_SDDR55, NULL,
- US_FL_FIX_INQUIRY ),
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-/* Submitted by Olaf Hering <olh@suse.de> */
-UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
- "Datafab Systems, Inc.",
- "USB to CF + SM Combo (LC1)",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-/* SM part - aeb <Andries.Brouwer@cwi.nl> */
-UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
- "Datafab Systems, Inc.",
- "USB to CF + SM Combo (LC1)",
- US_SC_SCSI, US_PR_SDDR55, NULL,
+ "CameraMate",
+ USB_SC_SCSI, USB_PR_CB, NULL,
US_FL_SINGLE_LUN ),
#endif
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-/* Reported by Felix Moeller <felix@derklecks.de>
- * in Germany this is sold by Hama with the productnumber 46952
- * as "DualSlot CompactFlash(TM) & MStick Drive USB"
- */
-UNUSUAL_DEV( 0x07c4, 0xa10b, 0x0000, 0xffff,
- "DataFab Systems Inc.",
- "USB CF+MS",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
-
-#endif
-
/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
* Only revision 1.13 tested (same for all of the above devices,
* based on the Datafab DF-UG-07 chip). Needed for US_FL_FIX_INQUIRY.
@@ -885,8 +1018,17 @@ UNUSUAL_DEV( 0x07c4, 0xa10b, 0x0000, 0xffff,
UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff,
"Datafab",
"KECF-USB",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ),
+
+/* Reported by Rauch Wolke <rauchwolke@gmx.net>
+ * and augmented by binbin <binbinsh@gmail.com> (Bugzilla #12882)
+ */
+UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff,
+ "Simple Tech/Datafab",
+ "CF+SM Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ),
/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
* to the USB storage specification in two ways:
@@ -895,23 +1037,50 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff,
* - They don't like the INQUIRY command. So we must handle this command
* of the SCSI layer ourselves.
* - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
- * bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB).
- * So don't remove the US_PR_CB override!
- * - Cameras with bcdDevice=0x9009 require the US_SC_8070 override.
+ * bInterfaceProtocol=0x00 (USB_PR_CBI) while others have 0x01 (USB_PR_CB).
+ * So don't remove the USB_PR_CB override!
+ * - Cameras with bcdDevice=0x9009 require the USB_SC_8070 override.
*/
UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999,
"Casio",
"QV DigitalCamera",
- US_SC_8070, US_PR_CB, NULL,
+ USB_SC_8070, USB_PR_CB, NULL,
US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ),
+/* Submitted by Oleksandr Chumachenko <ledest@gmail.com> */
+UNUSUAL_DEV( 0x07cf, 0x1167, 0x0100, 0x0100,
+ "Casio",
+ "EX-N1 DigitalCamera",
+ USB_SC_8070, USB_PR_DEVICE, NULL, 0),
+
/* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
"Samsung",
"Digimax 410",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY),
+/* Reported by Luciano Rocha <luciano@eurotux.com> */
+UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001,
+ "Argosy",
+ "Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported and patched by Nguyen Anh Quynh <aquynh@gmail.com> */
+UNUSUAL_DEV( 0x0840, 0x0084, 0x0001, 0x0001,
+ "Argosy",
+ "Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Martijn Hijdra <martijn.hijdra@gmail.com> */
+UNUSUAL_DEV( 0x0840, 0x0085, 0x0001, 0x0001,
+ "Argosy",
+ "Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Flag will support Bulk devices which use a standards-violating 32-byte
* Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with
@@ -921,9 +1090,44 @@ UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110,
"Grandtech",
"DC2MEGA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BULK32),
+/* Reported by <ttkspam@free.fr>
+ * The device reports a vendor-specific device class, requiring an
+ * explicit vendor/product match.
+ */
+UNUSUAL_DEV( 0x0851, 0x1542, 0x0002, 0x0002,
+ "MagicPixel",
+ "FW_Omega2",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
+/* Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+*/
+UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
+ "PanDigital",
+ "Photo Frame",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
+/* Submitted by Jan De Luyck <lkml@kcore.org> */
+UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
+ "CITIZEN",
+ "X1DE-USB",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN),
+
+/* Submitted by Dylan Taft <d13f00l@gmail.com>
+ * US_FL_IGNORE_RESIDUE Needed
+ */
+UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100,
+ "AIPTEK",
+ "Aiptek USB Keychain MP3 Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
/* Entry needed for flags. Moreover, all devices with this ID use
* bulk-only transport, but _some_ falsely report Control/Bulk instead.
@@ -933,7 +1137,7 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110,
UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100,
"Trumpion",
"t33520 USB Flash Card Controller",
- US_SC_DEVICE, US_PR_BULK, NULL,
+ USB_SC_DEVICE, USB_PR_BULK, NULL,
US_FL_NEED_OVERRIDE ),
/* Reported by Filippo Bardelli <filibard@libero.it>
@@ -942,23 +1146,33 @@ UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100,
UNUSUAL_DEV( 0x090a, 0x1050, 0x0100, 0x0100,
"Trumpion Microelectronics, Inc.",
"33520 USB Digital Voice Recorder",
- US_SC_UFI, US_PR_DEVICE, NULL,
+ USB_SC_UFI, USB_PR_DEVICE, NULL,
0),
/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
"Trumpion",
"MP3 player",
- US_SC_RBC, US_PR_BULK, NULL,
+ USB_SC_RBC, USB_PR_BULK, NULL,
0 ),
/* aeb */
UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
"Feiya",
"5-in-1 Card Reader",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Paul Hartman <paul.hartman+linux@gmail.com>
+ * This card reader returns "Illegal Request, Logical Block Address
+ * Out of Range" for the first READ(10) after a new card is inserted.
+ */
+UNUSUAL_DEV( 0x090c, 0x6000, 0x0100, 0x0100,
+ "Feiya",
+ "SD/SDHC Card Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_INITIAL_READ10 ),
+
/* This Pentax still camera is not conformant
* to the USB storage specification: -
* - It does not like the INQUIRY command. So we must handle this command
@@ -967,59 +1181,175 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
* Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
*/
UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
- "Pentax",
- "Optio 2/3/400",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
-
-
-/* Submitted by Per Winkvist <per.winkvist@uk.com> */
-UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
- "Pentax",
- "Optio S/S4",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
-
-#ifdef CONFIG_USB_STORAGE_ISD200
-UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
- "ATI",
- "USB Cable 205",
- US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+ "Pentax",
+ "Optio 2/3/400",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY ),
+
+/* These are virtual windows driver CDs, which the zd1211rw driver
+ * automatically converts into WLAN devices. */
+UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
+ "ZyXEL",
+ "G-220F USB-WLAN Install",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+
+UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101,
+ "SiteCom",
+ "WL-117 USB-WLAN Install",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+
+/* Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* iCON 225 */
+UNUSUAL_DEV( 0x0af0, 0x6971, 0x0000, 0x9999,
+ "Option N.V.",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init,
+ 0),
+
+/* Reported by F. Aben <f.aben@option.com>
+ * This device (wrongly) has a vendor-specific device descriptor.
+ * The entry is needed so usb-storage can bind to it's mass-storage
+ * interface as an interface driver */
+UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
+ "Option",
+ "GI 0401 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
0 ),
-#endif
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
- "Acomdata",
- "CF",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- US_FL_SINGLE_LUN ),
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
- "Acomdata",
- "SM",
- US_SC_SCSI, US_PR_SDDR55, NULL,
- US_FL_SINGLE_LUN ),
-#endif
+/* Reported by Jan Dumon <j.dumon@option.com>
+ * These devices (wrongly) have a vendor-specific device descriptor.
+ * These entries are needed so usb-storage can bind to their mass-storage
+ * interface as an interface driver */
+UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
+ "Option",
+ "GI 0431 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
-/* Submitted by: Nick Sillik <n.sillik@temple.edu>
- * Needed for OneTouch extension to usb-storage
- *
+UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000,
+ "Option",
+ "GI 0451 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000,
+ "Option",
+ "GI 0451 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000,
+ "Option",
+ "GI 0452 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000,
+ "Option",
+ "GI 0461 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000,
+ "Option",
+ "GI 0461 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000,
+ "Option",
+ "GI 033x SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+ "Option",
+ "GI 070x SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000,
+ "Option",
+ "GI 1505 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000,
+ "Option",
+ "GI 1509 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000,
+ "Option",
+ "GI 1515 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000,
+ "Option",
+ "GI 1215 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000,
+ "Option",
+ "GI 1505 SD-Card",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0 ),
+
+/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */
+UNUSUAL_DEV(0x0bc2, 0x2300, 0x0000, 0x9999,
+ "Seagate",
+ "Portable HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE),
+
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
+ "Seagate",
+ "FreeAgent Pro",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
+
+UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999,
+ "Maxtor",
+ "USB to SATA",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE),
+
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
+ * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
*/
-#ifdef CONFIG_USB_STORAGE_ONETOUCH
- UNUSUAL_DEV( 0x0d49, 0x7010, 0x0000, 0x9999,
- "Maxtor",
- "OneTouch External Harddrive",
- US_SC_DEVICE, US_PR_DEVICE, onetouch_connect_input,
- 0),
-#endif
+UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
+ "Unknown",
+ "Unknown",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
/* Submitted by Joris Struyve <joris@struyve.be> */
UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
"Medion",
"MD 7425",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY),
/*
@@ -1030,7 +1360,14 @@ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200,
"Jenoptik",
"JD 5200 z3",
- US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Reported by Jason Johnston <killean@shaw.ca> */
+UNUSUAL_DEV( 0x0dc4, 0x0073, 0x0000, 0x0000,
+ "Macpower Technology Co.LTD.",
+ "USB 2.0 3.5\" DEVICE",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
/* Reported by Lubomir Blaha <tritol@trilogic.cz>
* I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
@@ -1040,29 +1377,45 @@ UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200,
UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff,
"Netac",
"USB-CF-Card",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Reported by Edward Chapman (taken from linux-usb mailing list)
+ Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive */
+UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999,
+ "Netac",
+ "USB Flash Disk",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+
/* Patch by Stephan Walter <stephan.walter@epfl.ch>
* I don't know why, but it works... */
UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012,
"WINWARD",
"Music Disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Reported by Ian McConnell <ian at emit.demon.co.uk> */
UNUSUAL_DEV( 0x0dda, 0x0301, 0x0012, 0x0012,
"PNP_MP3",
"PNP_MP3 PLAYER",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Jim McCloskey <mcclosk@ucsc.edu> */
+UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0100,
+ "Cowon Systems",
+ "iAUDIO M5",
+ USB_SC_DEVICE, USB_PR_BULK, NULL,
+ US_FL_NEED_OVERRIDE ),
+
/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
"USB",
"Solid state disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* Submitted by Daniel Drake <dsd@gentoo.org>
@@ -1070,58 +1423,715 @@ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
UNUSUAL_DEV( 0x0ea0, 0x2168, 0x0110, 0x0110,
"Ours Technology",
"Flash Disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
/* Reported by Rastislav Stanik <rs_kernel@yahoo.com> */
UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110,
"USB",
"Flash Disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Benjamin Schiller <sbenni@gmx.de>
+ * It is also sold by Easylite as DJ 20 */
+UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103,
+ "Typhoon",
+ "My DJ 1820",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64),
+
+/* Patch by Leonid Petrov mail at lpetrov.net
+ * Reported by Robert Spitzenpfeil <robert@spitzenpfeil.org>
+ * http://www.qbik.ch/usb/devices/showdev.php?id=1705
+ * Updated to 103 device by MJ Ray mjr at phonecoop.coop
+ */
+UNUSUAL_DEV( 0x0f19, 0x0103, 0x0100, 0x0100,
+ "Oracom Co., Ltd",
+ "ORC-200M",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* David Kuehling <dvdkhlng@gmx.de>:
+ * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI
+ * errors when trying to write.
+ */
+UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100,
+ "C-MEX",
+ "A-VOX",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Submitted by Nick Holloway */
+UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
+ "VTech",
+ "Kidizoom",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
+/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */
+UNUSUAL_DEV( 0x0fca, 0x8004, 0x0201, 0x0201,
+ "Research In Motion",
+ "BlackBerry Bold 9000",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
/* Reported by Michael Stattmann <michael@stattmann.com> */
UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
"Sony Ericsson",
"V800-Vodafone 802",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_WP_DETECT ),
+/* Reported by The Solutor <thesolutor@gmail.com> */
+UNUSUAL_DEV( 0x0fce, 0xd0e1, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "MD400",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
+/* Reported by Jan Mate <mate@fiit.stuba.sk>
+ * and by Soeren Sonnenburg <kernel@nn7.de> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
+UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "M600i",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
+UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P1i",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
+ * Devices with bcd > 110 seem to not need it while those
+ * with bcd < 110 appear to need it.
*/
-UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
"Desknote",
"UCR-61S2B",
- US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+UNUSUAL_DEV( 0x1058, 0x0704, 0x0000, 0x9999,
+ "Western Digital",
+ "External HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE),
+
+/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */
+UNUSUAL_DEV(0x1058, 0x070a, 0x0000, 0x9999,
+ "Western Digital",
+ "My Passport HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE),
+
+/* Reported by Fabio Venturi <f.venturi@tdnet.it>
+ * The device reports a vendor-specific bDeviceClass.
+ */
+UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100,
+ "Actions Semiconductor",
+ "Mtp device",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ 0),
+
+/* Reported by Pascal Terjan <pterjan@mandriva.com>
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000,
+ "D-Link",
+ "USB Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE),
+
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
+ "Sierra Wireless",
+ "USB MMC Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, sierra_ms_init,
+ 0),
+
+/* Reported by Jaco Kroon <jaco@kroon.co.za>
+ * The usb-storage module found on the Digitech GNX4 (and supposedly other
+ * devices) misbehaves and causes a bunch of invalid I/O errors.
+ */
+UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
+ "Digitech HMG",
+ "DigiTech Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by fangxiaozhi <huananhu@huawei.com>
+ * This brings the HUAWEI data card devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1402, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1404, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1407, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x140F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x141F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1420, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1421, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1422, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1423, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1424, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1425, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1426, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1427, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1428, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1429, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x142F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1430, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1431, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1432, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1433, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1434, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1435, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1436, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1437, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1438, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x1439, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143A, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143B, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143C, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143D, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143E, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+UNUSUAL_DEV( 0x12d1, 0x143F, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",
"Dimage Z10",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
0 ),
/* Reported by Kotrla Vitezslav <kotrla@ceb.cz> */
UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110,
"SWISSBIT",
"Black Silver",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Qinglin Ye <yestyle@gmail.com> */
+UNUSUAL_DEV( 0x13fe, 0x3600, 0x0100, 0x0100,
+ "Kingston",
+ "DT 101 G2",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BULK_IGNORE_TAG ),
+
+/* Reported by Francesco Foresti <frafore@tiscali.it> */
+UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201,
+ "Super Top",
+ "IDE DEVICE",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Michael Büsch <m@bues.ch> */
+UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0114,
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BROKEN_FUA ),
+
+/* Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br>
+ * JMicron responds to USN and several other SCSI ioctls with a
+ * residue that causes subsequent I/O requests to fail. */
+UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100,
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Robert Schedel <r.schedel@yahoo.de>
+ * Note: this is a 'super top' device like the above 14cd/6600 device */
+UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
+ "Teac",
+ "HD-35PUK-B",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Oliver Neukum <oneukum@suse.com> */
+UNUSUAL_DEV( 0x174c, 0x55aa, 0x0100, 0x0100,
+ "ASMedia",
+ "AS2105",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NEEDS_CAP16),
+
+/* Reported by Jesse Feddema <jdfeddema@gmail.com> */
+UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000,
+ "Yarvik",
+ "PMP400",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Hans de Goede <hdegoede@redhat.com>
+ * These Appotech controllers are found in Picture Frames, they provide a
+ * (buggy) emulation of a cdrom drive which contains the windows software
+ * Uploading of pictures happens over the corresponding /dev/sg device. */
+UNUSUAL_DEV( 0x1908, 0x1315, 0x0000, 0x0000,
+ "BUILDWIN",
+ "Photo Frame",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BAD_SENSE ),
+UNUSUAL_DEV( 0x1908, 0x1320, 0x0000, 0x0000,
+ "BUILDWIN",
+ "Photo Frame",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BAD_SENSE ),
+UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
+ "BUILDWIN",
+ "Photo Frame",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_READ_DISC_INFO ),
+
+/* Reported by Sven Geggus <sven-usbst@geggus.net>
+ * This encrypted pen drive returns bogus data for the initial READ(10).
+ */
+UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200,
+ "Corsair",
+ "Padlock v2",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_INITIAL_READ10 ),
+
+/* Patch by Richard Schütz <r.schtz@t-online.de>
+ * This external hard drive enclosure uses a JMicron chip which
+ * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
+UNUSUAL_DEV( 0x1e68, 0x001b, 0x0000, 0x0000,
+ "TrekStor GmbH & Co. KG",
+ "DataStation maxi g.u",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Jasper Mackenzie <scarletpimpernal@hotmail.com> */
+UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000,
+ "Coby Electronics",
+ "MP3 Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
+UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
+ "ST",
+ "2A",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
+ * and Renato Perini <rperini@email.it>
+ */
+UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001,
+ "Motorola",
+ "RAZR V3x",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/*
+ * Patch by Constantin Baranov <const@tltsu.ru>
+ * Report by Andreas Koenecke.
+ * Motorola ROKR Z6.
+ */
+UNUSUAL_DEV( 0x22b8, 0x6426, 0x0101, 0x0101,
+ "Motorola",
+ "MSnc.",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY | US_FL_BULK_IGNORE_TAG),
+
/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
"MPIO",
"HS200",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_GO_SLOW ),
-#ifdef CONFIG_USB_STORAGE_SDDR55
-UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999,
- "Sandisk",
- "ImageMate SDDR55",
- US_SC_SCSI, US_PR_SDDR55, NULL,
- US_FL_SINGLE_LUN),
+/* Reported by Frederic Marchal <frederic.marchal@wowcompany.com>
+ * Mio Moov 330
+ */
+UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000,
+ "Mitac",
+ "Mio DigiWalker USB Sync",
+ USB_SC_DEVICE,USB_PR_DEVICE,NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
+UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
+ "iRiver",
+ "MP3 T10",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Sergey Pinaev <dfo@antex.ru> */
+UNUSUAL_DEV( 0x4102, 0x1059, 0x0000, 0x0000,
+ "iRiver",
+ "P7K",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/*
+ * David Härdeman <david@2gen.com>
+ * The key makes the SCSI stack print confusing (but harmless) messages
+ */
+UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100,
+ "Iomega",
+ "Micro Mini 1GB",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/*
+ * Nick Bowler <nbowler@elliptictech.com>
+ * SCSI stack spams (otherwise harmless) error messages.
+ */
+UNUSUAL_DEV( 0xc251, 0x4003, 0x0100, 0x0100,
+ "Keil Software, Inc.",
+ "V2M MotherBoard",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
+/* Reported by Andrew Simmons <andrew.simmons@gmail.com> */
+UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
+ "DataStor",
+ "USB4500 FW1.04",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_CAPACITY_HEURISTICS),
+
+/* Reported by Alessio Treglia <quadrispro@ubuntu.com> */
+UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001,
+ "TGE",
+ "Digital MP3 Audio Player",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
+
+/* Unusual uas devices */
+#if IS_ENABLED(CONFIG_USB_UAS)
+#include "unusual_uas.h"
#endif
+
+/* Control/Bulk transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_CB),
+USUAL_DEV(USB_SC_8020, USB_PR_CB),
+USUAL_DEV(USB_SC_QIC, USB_PR_CB),
+USUAL_DEV(USB_SC_UFI, USB_PR_CB),
+USUAL_DEV(USB_SC_8070, USB_PR_CB),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CB),
+
+/* Control/Bulk/Interrupt transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_CBI),
+USUAL_DEV(USB_SC_8020, USB_PR_CBI),
+USUAL_DEV(USB_SC_QIC, USB_PR_CBI),
+USUAL_DEV(USB_SC_UFI, USB_PR_CBI),
+USUAL_DEV(USB_SC_8070, USB_PR_CBI),
+USUAL_DEV(USB_SC_SCSI, USB_PR_CBI),
+
+/* Bulk-only transport for all SubClass values */
+USUAL_DEV(USB_SC_RBC, USB_PR_BULK),
+USUAL_DEV(USB_SC_8020, USB_PR_BULK),
+USUAL_DEV(USB_SC_QIC, USB_PR_BULK),
+USUAL_DEV(USB_SC_UFI, USB_PR_BULK),
+USUAL_DEV(USB_SC_8070, USB_PR_BULK),
+USUAL_DEV(USB_SC_SCSI, USB_PR_BULK),
diff --git a/drivers/usb/storage/isd200.h b/drivers/usb/storage/unusual_ene_ub6250.h
index 0a35f4fa78f..5667f5d365c 100644
--- a/drivers/usb/storage/isd200.h
+++ b/drivers/usb/storage/unusual_ene_ub6250.h
@@ -1,11 +1,4 @@
-/* Header File for In-System Design, Inc. ISD200 ASIC
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 In-System Design, Inc. (support@in-system.com)
- *
- * See isd200.c for more information.
+/*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -22,10 +15,12 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef _USB_ISD200_H
-#define _USB_ISD200_H
+#if defined(CONFIG_USB_STORAGE_ENE_UB6250) || \
+ defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE)
-extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us);
-extern int isd200_Initialization(struct us_data *us);
+UNUSUAL_DEV(0x0cf2, 0x6250, 0x0000, 0x9999,
+ "ENE",
+ "ENE UB6250 reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
-#endif
+#endif /* defined(CONFIG_USB_STORAGE_ENE_UB6250) || ... */
diff --git a/drivers/usb/storage/sddr55.h b/drivers/usb/storage/unusual_freecom.h
index d6bd32f6c9f..59a261155b9 100644
--- a/drivers/usb/storage/sddr55.h
+++ b/drivers/usb/storage/unusual_freecom.h
@@ -1,12 +1,4 @@
-/* Driver for SanDisk SDDR-55 SmartMedia reader
- * Header File
- *
- * $Id:$
- *
- * Current development and maintenance by:
- * (c) 2002 Simon Munton
- *
- * See sddr55.c for more explanation
+/* Unusual Devices File for the Freecom USB/IDE adaptor
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -23,12 +15,12 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef _USB_SHUTTLE_EUSB_SDDR55_H
-#define _USB_SHUTTLE_EUSB_SDDR55_H
-
-/* Sandisk SDDR-55 stuff */
+#if defined(CONFIG_USB_STORAGE_FREECOM) || \
+ defined(CONFIG_USB_STORAGE_FREECOM_MODULE)
-extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int sddr55_reset(struct us_data *us);
+UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
+ "Freecom",
+ "USB-IDE",
+ USB_SC_QIC, USB_PR_FREECOM, init_freecom, 0),
-#endif
+#endif /* defined(CONFIG_USB_STORAGE_FREECOM) || ... */
diff --git a/drivers/usb/storage/unusual_isd200.h b/drivers/usb/storage/unusual_isd200.h
new file mode 100644
index 00000000000..14cca0c4830
--- /dev/null
+++ b/drivers/usb/storage/unusual_isd200.h
@@ -0,0 +1,57 @@
+/* Unusual Devices File for In-System Design, Inc. ISD200 ASIC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_ISD200) || \
+ defined(CONFIG_USB_STORAGE_ISD200_MODULE)
+
+UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110,
+ "Sony",
+ "Portable USB Harddrive V2",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110,
+ "In-System",
+ "USB/IDE Bridge (ATA/ATAPI)",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+UNUSUAL_DEV( 0x05ab, 0x0301, 0x0100, 0x0110,
+ "In-System",
+ "Portable USB Harddrive V2",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+UNUSUAL_DEV( 0x05ab, 0x0351, 0x0100, 0x0110,
+ "In-System",
+ "Portable USB Harddrive V2",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110,
+ "In-System",
+ "USB Storage Adapter V2",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
+ "ATI",
+ "USB Cable 205",
+ USB_SC_ISD200, USB_PR_BULK, isd200_Initialization,
+ 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ISD200) || ... */
diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/unusual_jumpshot.h
index 81b464cfcc1..54be78b5d64 100644
--- a/drivers/usb/storage/dpcm.h
+++ b/drivers/usb/storage/unusual_jumpshot.h
@@ -1,15 +1,4 @@
-/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
- *
- * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $
- *
- * DPCM driver v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 Brian Webb (webbb@earthlink.net)
- *
- * See dpcm.c for more explanation
+/* Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -26,9 +15,13 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef _MICROTECH_DPCM_USB_H
-#define _MICROTECH_DPCM_USB_H
+#if defined(CONFIG_USB_STORAGE_JUMPSHOT) || \
+ defined(CONFIG_USB_STORAGE_JUMPSHOT_MODULE)
-extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us);
+UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
+ "Lexar",
+ "Jumpshot USB CF Reader",
+ USB_SC_SCSI, USB_PR_JUMPSHOT, NULL,
+ US_FL_NEED_OVERRIDE),
-#endif
+#endif /* defined(CONFIG_USB_STORAGE_JUMPSHOT) || ... */
diff --git a/drivers/usb/storage/unusual_karma.h b/drivers/usb/storage/unusual_karma.h
new file mode 100644
index 00000000000..6df03972a22
--- /dev/null
+++ b/drivers/usb/storage/unusual_karma.h
@@ -0,0 +1,26 @@
+/* Unusual Devices File for the Rio Karma
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_KARMA) || \
+ defined(CONFIG_USB_STORAGE_KARMA_MODULE)
+
+UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
+ "Rio",
+ "Rio Karma",
+ USB_SC_SCSI, USB_PR_KARMA, rio_karma_init, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_KARMA) || ... */
diff --git a/drivers/usb/storage/unusual_onetouch.h b/drivers/usb/storage/unusual_onetouch.h
new file mode 100644
index 00000000000..0abb819c740
--- /dev/null
+++ b/drivers/usb/storage/unusual_onetouch.h
@@ -0,0 +1,36 @@
+/* Unusual Devices File for the Maxtor OneTouch USB hard drive's button
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_ONETOUCH) || \
+ defined(CONFIG_USB_STORAGE_ONETOUCH_MODULE)
+
+/* Submitted by: Nick Sillik <n.sillik@temple.edu>
+ * Needed for OneTouch extension to usb-storage
+ */
+UNUSUAL_DEV( 0x0d49, 0x7000, 0x0000, 0x9999,
+ "Maxtor",
+ "OneTouch External Harddrive",
+ USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input,
+ 0),
+
+UNUSUAL_DEV( 0x0d49, 0x7010, 0x0000, 0x9999,
+ "Maxtor",
+ "OneTouch External Harddrive",
+ USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input,
+ 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_ONETOUCH) || ... */
diff --git a/drivers/usb/storage/unusual_realtek.h b/drivers/usb/storage/unusual_realtek.h
new file mode 100644
index 00000000000..e41f50c95ed
--- /dev/null
+++ b/drivers/usb/storage/unusual_realtek.h
@@ -0,0 +1,41 @@
+/* Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#if defined(CONFIG_USB_STORAGE_REALTEK) || \
+ defined(CONFIG_USB_STORAGE_REALTEK_MODULE)
+
+UNUSUAL_DEV(0x0bda, 0x0138, 0x0000, 0x9999,
+ "Realtek",
+ "USB Card Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0158, 0x0000, 0x9999,
+ "Realtek",
+ "USB Card Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+UNUSUAL_DEV(0x0bda, 0x0159, 0x0000, 0x9999,
+ "Realtek",
+ "USB Card Reader",
+ USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_REALTEK) || ... */
diff --git a/drivers/usb/storage/unusual_sddr09.h b/drivers/usb/storage/unusual_sddr09.h
new file mode 100644
index 00000000000..59a7e37b6c1
--- /dev/null
+++ b/drivers/usb/storage/unusual_sddr09.h
@@ -0,0 +1,56 @@
+/* Unusual Devices File for SanDisk SDDR-09 SmartMedia reader
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_SDDR09) || \
+ defined(CONFIG_USB_STORAGE_SDDR09_MODULE)
+
+UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate (DPCM_USB)",
+ USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0),
+
+UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR09",
+ USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+ 0),
+
+/* This entry is from Andries.Brouwer@cwi.nl */
+UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
+ "SCM Microsystems",
+ "eUSB SmartMedia / CompactFlash Adapter",
+ USB_SC_SCSI, USB_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,
+ 0),
+
+UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
+ "Olympus",
+ "Camedia MAUSB-2",
+ USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+ 0),
+
+UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR-09",
+ USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init,
+ 0),
+
+UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate (DPCM_USB)",
+ USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_SDDR09) || ... */
diff --git a/drivers/usb/storage/unusual_sddr55.h b/drivers/usb/storage/unusual_sddr55.h
new file mode 100644
index 00000000000..fcb7e12c598
--- /dev/null
+++ b/drivers/usb/storage/unusual_sddr55.h
@@ -0,0 +1,44 @@
+/* Unusual Devices File for SanDisk SDDR-55 SmartMedia reader
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_SDDR55) || \
+ defined(CONFIG_USB_STORAGE_SDDR55_MODULE)
+
+/* Contributed by Peter Waechtler */
+UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999,
+ "Datafab",
+ "MDSM-B reader",
+ USB_SC_SCSI, USB_PR_SDDR55, NULL,
+ US_FL_FIX_INQUIRY),
+
+/* SM part - aeb <Andries.Brouwer@cwi.nl> */
+UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
+ "Datafab Systems, Inc.",
+ "USB to CF + SM Combo (LC1)",
+ USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+ "Acomdata",
+ "SM",
+ USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999,
+ "Sandisk",
+ "ImageMate SDDR55",
+ USB_SC_SCSI, USB_PR_SDDR55, NULL, 0),
+
+#endif /* defined(CONFIG_USB_STORAGE_SDDR55) || ... */
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
new file mode 100644
index 00000000000..7244444df8e
--- /dev/null
+++ b/drivers/usb/storage/unusual_uas.h
@@ -0,0 +1,52 @@
+/* Driver for USB Attached SCSI devices - Unusual Devices File
+ *
+ * (c) 2013 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the same file for the usb-storage driver, which is:
+ * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * IMPORTANT NOTE: This file must be included in another file which defines
+ * a UNUSUAL_DEV macro before this file is included.
+ */
+
+/*
+ * If you edit this file, please try to keep it sorted first by VendorID,
+ * then by ProductID.
+ *
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ * - a patch that adds the entry for your device, including your
+ * email address right above the entry (plus maybe a brief
+ * explanation of the reason for the entry),
+ * - lsusb -v output for the device
+ * Send your submission to Hans de Goede <hdegoede@redhat.com>
+ * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
+ */
+
+/*
+ * This is an example entry for the US_FL_IGNORE_UAS flag. Once we have an
+ * actual entry using US_FL_IGNORE_UAS this entry should be removed.
+ *
+ * UNUSUAL_DEV( 0xabcd, 0x1234, 0x0100, 0x0100,
+ * "Example",
+ * "Storage with broken UAS",
+ * USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ * US_FL_IGNORE_UAS),
+ */
diff --git a/drivers/usb/storage/unusual_usbat.h b/drivers/usb/storage/unusual_usbat.h
new file mode 100644
index 00000000000..38e79c4e6d6
--- /dev/null
+++ b/drivers/usb/storage/unusual_usbat.h
@@ -0,0 +1,43 @@
+/* Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#if defined(CONFIG_USB_STORAGE_USBAT) || \
+ defined(CONFIG_USB_STORAGE_USBAT_MODULE)
+
+UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
+ "HP",
+ "CD-Writer+ 8200e",
+ USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0),
+
+UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
+ "HP",
+ "CD-Writer+ CD-4e",
+ USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0),
+
+UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
+ "Shuttle/SCM",
+ "USBAT-02",
+ USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash,
+ US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005,
+ "Sandisk",
+ "ImageMate SDDR-05b",
+ USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash,
+ US_FL_SINGLE_LUN),
+
+#endif /* defined(CONFIG_USB_STORAGE_USBAT) || ... */
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 3847ebed2aa..f1c96261a50 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,13 +1,11 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.75 2002/04/22 03:39:43 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
- * (c) 2003 Alan Stern (stern@rowland.harvard.edu)
+ * (c) 2003-2009 Alan Stern (stern@rowland.harvard.edu)
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
@@ -47,14 +45,18 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
+#ifdef CONFIG_USB_STORAGE_DEBUG
+#define DEBUG
+#endif
+
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/suspend.h>
+#include <linux/freezer.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/utsname.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -67,32 +69,11 @@
#include "debug.h"
#include "initializers.h"
-#ifdef CONFIG_USB_STORAGE_USBAT
-#include "shuttle_usbat.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR09
-#include "sddr09.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-#include "sddr55.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_DPCM
-#include "dpcm.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_FREECOM
-#include "freecom.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_ISD200
-#include "isd200.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-#include "datafab.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-#include "jumpshot.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_ONETOUCH
-#include "onetouch.h"
+#include "sierra_ms.h"
+#include "option_ms.h"
+
+#if IS_ENABLED(CONFIG_USB_UAS)
+#include "uas-detect.h"
#endif
/* Some informational data */
@@ -100,64 +81,20 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
-static unsigned int delay_use = 5;
+static unsigned int delay_use = 1;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
+static char quirks[128];
+module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
-/* The entries in this table, except for final ones here
- * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
- * line for line with the entries of us_unsuaul_dev_list[].
+/*
+ * The entries in this table correspond, line for line,
+ * with the entries in usb_storage_usb_ids[], defined in usual-tables.c.
*/
-#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
- vendorName, productName,useProtocol, useTransport, \
- initFunction, flags) \
-{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
-
-static struct usb_device_id storage_usb_ids [] = {
-
-# include "unusual_devs.h"
-#undef UNUSUAL_DEV
- /* Control/Bulk transport for all SubClass values */
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
-
- /* Control/Bulk/Interrupt transport for all SubClass values */
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
-
- /* Bulk-only transport for all SubClass values */
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
- { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
-
- /* Terminating entry */
- { }
-};
-
-MODULE_DEVICE_TABLE (usb, storage_usb_ids);
-
-/* This is the list of devices we recognize, along with their flag data */
-
/* The vendor name should be kept at eight characters or less, and
* the product name should be kept at 16 characters or less. If a device
* has the US_FL_FIX_INQUIRY flag, then the vendor and product names
@@ -167,7 +104,6 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
* are free to use as many characters as you like.
*/
-#undef UNUSUAL_DEV
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
@@ -177,94 +113,150 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
.useProtocol = use_protocol, \
.useTransport = use_transport, \
.initFunction = init_function, \
- .flags = Flags, \
+}
+
+#define COMPLIANT_DEV UNUSUAL_DEV
+
+#define USUAL_DEV(use_protocol, use_transport) \
+{ \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+}
+
+#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ .vendorName = vendor_name, \
+ .productName = product_name, \
+ .useProtocol = use_protocol, \
+ .useTransport = use_transport, \
+ .initFunction = init_function, \
}
static struct us_unusual_dev us_unusual_dev_list[] = {
-# include "unusual_devs.h"
-# undef UNUSUAL_DEV
- /* Control/Bulk transport for all SubClass values */
- { .useProtocol = US_SC_RBC,
- .useTransport = US_PR_CB},
- { .useProtocol = US_SC_8020,
- .useTransport = US_PR_CB},
- { .useProtocol = US_SC_QIC,
- .useTransport = US_PR_CB},
- { .useProtocol = US_SC_UFI,
- .useTransport = US_PR_CB},
- { .useProtocol = US_SC_8070,
- .useTransport = US_PR_CB},
- { .useProtocol = US_SC_SCSI,
- .useTransport = US_PR_CB},
-
- /* Control/Bulk/Interrupt transport for all SubClass values */
- { .useProtocol = US_SC_RBC,
- .useTransport = US_PR_CBI},
- { .useProtocol = US_SC_8020,
- .useTransport = US_PR_CBI},
- { .useProtocol = US_SC_QIC,
- .useTransport = US_PR_CBI},
- { .useProtocol = US_SC_UFI,
- .useTransport = US_PR_CBI},
- { .useProtocol = US_SC_8070,
- .useTransport = US_PR_CBI},
- { .useProtocol = US_SC_SCSI,
- .useTransport = US_PR_CBI},
-
- /* Bulk-only transport for all SubClass values */
- { .useProtocol = US_SC_RBC,
- .useTransport = US_PR_BULK},
- { .useProtocol = US_SC_8020,
- .useTransport = US_PR_BULK},
- { .useProtocol = US_SC_QIC,
- .useTransport = US_PR_BULK},
- { .useProtocol = US_SC_UFI,
- .useTransport = US_PR_BULK},
- { .useProtocol = US_SC_8070,
- .useTransport = US_PR_BULK},
- { .useProtocol = US_SC_SCSI,
- .useTransport = US_PR_BULK},
-
- /* Terminating entry */
- { NULL }
+# include "unusual_devs.h"
+ { } /* Terminating entry */
};
+static struct us_unusual_dev for_dynamic_ids =
+ USUAL_DEV(USB_SC_SCSI, USB_PR_BULK);
+
+#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
+#undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
+
+#ifdef CONFIG_LOCKDEP
+
+static struct lock_class_key us_interface_key[USB_MAXINTERFACES];
+
+static void us_set_lock_class(struct mutex *mutex,
+ struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_config *config = udev->actconfig;
+ int i;
+
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ if (config->interface[i] == intf)
+ break;
+ }
+
+ BUG_ON(i == config->desc.bNumInterfaces);
+
+ lockdep_set_class(mutex, &us_interface_key[i]);
+}
+
+#else
+
+static void us_set_lock_class(struct mutex *mutex,
+ struct usb_interface *intf)
+{
+}
+
+#endif
#ifdef CONFIG_PM /* Minimal support for suspend and resume */
-static int storage_suspend(struct usb_interface *iface, pm_message_t message)
+int usb_stor_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
/* Wait until no command is running */
- down(&us->dev_semaphore);
+ mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __FUNCTION__);
- iface->dev.power.power_state.event = message.event;
+ if (us->suspend_resume_hook)
+ (us->suspend_resume_hook)(us, US_SUSPEND);
/* When runtime PM is working, we'll set a flag to indicate
* whether we should autoresume when a SCSI request arrives. */
- up(&us->dev_semaphore);
+ mutex_unlock(&us->dev_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(usb_stor_suspend);
-static int storage_resume(struct usb_interface *iface)
+int usb_stor_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- down(&us->dev_semaphore);
+ mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __FUNCTION__);
- iface->dev.power.power_state.event = PM_EVENT_ON;
+ if (us->suspend_resume_hook)
+ (us->suspend_resume_hook)(us, US_RESUME);
- up(&us->dev_semaphore);
+ mutex_unlock(&us->dev_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(usb_stor_resume);
+
+int usb_stor_reset_resume(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ /* Report the reset to the SCSI core */
+ usb_stor_report_bus_reset(us);
+
+ /* FIXME: Notify the subdrivers that they need to reinitialize
+ * the device */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_reset_resume);
#endif /* CONFIG_PM */
/*
+ * The next two routines get called just before and just after
+ * a USB port reset, whether from this driver or a different one.
+ */
+
+int usb_stor_pre_reset(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ /* Make sure no command runs during the reset */
+ mutex_lock(&us->dev_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_pre_reset);
+
+int usb_stor_post_reset(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ /* Report the reset to the SCSI core */
+ usb_stor_report_bus_reset(us);
+
+ /* FIXME: Notify the subdrivers that they need to reinitialize
+ * the device */
+
+ mutex_unlock(&us->dev_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_stor_post_reset);
+
+/*
* fill_inquiry_response takes an unsigned char array (which must
* be at least 36 characters) and populates the vendor name,
* product name, and revision fields. Then the array is copied
@@ -276,27 +268,28 @@ static int storage_resume(struct usb_interface *iface)
void fill_inquiry_response(struct us_data *us, unsigned char *data,
unsigned int data_len)
{
- if (data_len<36) // You lose.
+ if (data_len < 36) /* You lose. */
return;
- if(data[0]&0x20) { /* USB device currently not connected. Return
+ memset(data+8, ' ', 28);
+ if (data[0]&0x20) { /* USB device currently not connected. Return
peripheral qualifier 001b ("...however, the
physical device is not currently connected
to this logical unit") and leave vendor and
product identification empty. ("If the target
does store some of the INQUIRY data on the
- device, it may return zeros or ASCII spaces
+ device, it may return zeros or ASCII spaces
(20h) in those fields until the data is
available from the device."). */
- memset(data+8,0,28);
} else {
u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
- memcpy(data+8, us->unusual_dev->vendorName,
- strlen(us->unusual_dev->vendorName) > 8 ? 8 :
- strlen(us->unusual_dev->vendorName));
- memcpy(data+16, us->unusual_dev->productName,
- strlen(us->unusual_dev->productName) > 16 ? 16 :
- strlen(us->unusual_dev->productName));
+ int n;
+
+ n = strlen(us->unusual_dev->vendorName);
+ memcpy(data+8, us->unusual_dev->vendorName, min(8, n));
+ n = strlen(us->unusual_dev->productName);
+ memcpy(data+16, us->unusual_dev->productName, min(16, n));
+
data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
@@ -305,83 +298,84 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data,
usb_stor_set_xfer_buf(data, data_len, us->srb);
}
+EXPORT_SYMBOL_GPL(fill_inquiry_response);
static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- current->flags |= PF_NOFREEZE;
-
- for(;;) {
- US_DEBUGP("*** thread sleeping.\n");
- if(down_interruptible(&us->sema))
+ for (;;) {
+ usb_stor_dbg(us, "*** thread sleeping\n");
+ if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
-
- US_DEBUGP("*** thread awakened.\n");
- /* lock the device pointers */
- down(&(us->dev_semaphore));
+ usb_stor_dbg(us, "*** thread awakened\n");
- /* if the device has disconnected, we are free to exit */
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- US_DEBUGP("-- exiting\n");
- up(&(us->dev_semaphore));
- break;
- }
+ /* lock the device pointers */
+ mutex_lock(&(us->dev_mutex));
/* lock access to the state */
scsi_lock(host);
+ /* When we are called with no command pending, we're done */
+ if (us->srb == NULL) {
+ scsi_unlock(host);
+ mutex_unlock(&us->dev_mutex);
+ usb_stor_dbg(us, "-- exiting\n");
+ break;
+ }
+
/* has the command timed out *already* ? */
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
us->srb->result = DID_ABORT << 16;
goto SkipForAbort;
}
scsi_unlock(host);
- /* reject the command if the direction indicator
+ /* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
- US_DEBUGP("UNKNOWN data direction\n");
+ usb_stor_dbg(us, "UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
- else if (us->srb->device->id &&
- !(us->flags & US_FL_SCM_MULT_TARG)) {
- US_DEBUGP("Bad target number (%d:%d)\n",
- us->srb->device->id, us->srb->device->lun);
+ else if (us->srb->device->id &&
+ !(us->fflags & US_FL_SCM_MULT_TARG)) {
+ usb_stor_dbg(us, "Bad target number (%d:%d)\n",
+ us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
else if (us->srb->device->lun > us->max_lun) {
- US_DEBUGP("Bad LUN (%d:%d)\n",
- us->srb->device->id, us->srb->device->lun);
+ usb_stor_dbg(us, "Bad LUN (%d:%d)\n",
+ us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
- /* Handle those devices which need us to fake
+ /* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
- (us->flags & US_FL_FIX_INQUIRY)) {
+ (us->fflags & US_FL_FIX_INQUIRY)) {
unsigned char data_ptr[36] = {
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
- US_DEBUGP("Faking INQUIRY command\n");
+ usb_stor_dbg(us, "Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = SAM_STAT_GOOD;
}
/* we've got a command, let's do it! */
else {
- US_DEBUG(usb_stor_show_command(us->srb));
+ US_DEBUG(usb_stor_show_command(us, us->srb));
us->proto_handler(us->srb, us);
+ usb_mark_last_busy(us->pusb_dev);
}
/* lock access to the state */
@@ -389,12 +383,12 @@ static int usb_stor_control_thread(void * __us)
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
- US_DEBUGP("scsi cmd done, result=0x%x\n",
- us->srb->result);
+ usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
+ us->srb->result);
us->srb->scsi_done(us->srb);
} else {
SkipForAbort:
- US_DEBUGP("scsi command aborted\n");
+ usb_stor_dbg(us, "scsi command aborted\n");
}
/* If an abort request was received we need to signal that
@@ -402,12 +396,12 @@ SkipForAbort:
* the TIMED_OUT flag, not srb->result == DID_ABORT, because
* the timeout might have occurred after the command had
* already completed with a different result code. */
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
complete(&(us->notify));
/* Allow USB transfers to resume */
- clear_bit(US_FLIDX_ABORTING, &us->flags);
- clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
+ clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
}
/* finished working on this command */
@@ -415,27 +409,19 @@ SkipForAbort:
scsi_unlock(host);
/* unlock the device pointers */
- up(&(us->dev_semaphore));
+ mutex_unlock(&us->dev_mutex);
} /* for (;;) */
- scsi_host_put(host);
-
- /* notify the exit routine that we're actually exiting now
- *
- * complete()/wait_for_completion() is similar to up()/down(),
- * except that complete() is safe in the case where the structure
- * is getting deleted in a parallel mode of execution (i.e. just
- * after the down() -- that's necessary for the thread-shutdown
- * case.
- *
- * complete_and_exit() goes even further than this -- it is safe in
- * the case that the thread of the caller is going away (not just
- * the structure) -- this is necessary for the module-remove case.
- * This is important in preemption kernels, which transfer the flow
- * of execution immediately upon a complete().
- */
- complete_and_exit(&threads_gone, 0);
-}
+ /* Wait until we are told to stop */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (kthread_should_stop())
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+ return 0;
+}
/***********************************************************************
* Device probing and disconnecting
@@ -444,71 +430,167 @@ SkipForAbort:
/* Associate our private data with the USB device */
static int associate_dev(struct us_data *us, struct usb_interface *intf)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
-
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
- US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
- le16_to_cpu(us->pusb_dev->descriptor.idVendor),
- le16_to_cpu(us->pusb_dev->descriptor.idProduct),
- le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
- US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
- intf->cur_altsetting->desc.bInterfaceSubClass,
- intf->cur_altsetting->desc.bInterfaceProtocol);
+ usb_stor_dbg(us, "Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
+ le16_to_cpu(us->pusb_dev->descriptor.idVendor),
+ le16_to_cpu(us->pusb_dev->descriptor.idProduct),
+ le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
+ usb_stor_dbg(us, "Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
+ intf->cur_altsetting->desc.bInterfaceSubClass,
+ intf->cur_altsetting->desc.bInterfaceProtocol);
/* Store our private data in the interface */
usb_set_intfdata(intf, us);
- /* Allocate the device-related DMA-mapped buffers */
- us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),
- GFP_KERNEL, &us->cr_dma);
- if (!us->cr) {
- US_DEBUGP("usb_ctrlrequest allocation failed\n");
+ /* Allocate the control/setup and DMA-mapped buffers */
+ us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
+ if (!us->cr)
return -ENOMEM;
- }
- us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,
+ us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE,
GFP_KERNEL, &us->iobuf_dma);
if (!us->iobuf) {
- US_DEBUGP("I/O buffer allocation failed\n");
+ usb_stor_dbg(us, "I/O buffer allocation failed\n");
return -ENOMEM;
}
+ return 0;
+}
+
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+/* Adjust device flags based on the "quirks=" module parameter */
+void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)
+{
+ char *p;
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+ unsigned f = 0;
+ unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE |
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_UAS |
+ US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
+ US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
+ US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
+ US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT |
+ US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 |
+ US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE);
+
+ p = quirks;
+ while (*p) {
+ /* Each entry consists of VID:PID:flags */
+ if (vid == simple_strtoul(p, &p, 16) &&
+ *p == ':' &&
+ pid == simple_strtoul(p+1, &p, 16) &&
+ *p == ':')
+ break;
+
+ /* Move forward to the next entry */
+ while (*p) {
+ if (*p++ == ',')
+ break;
+ }
+ }
+ if (!*p) /* No match */
+ return;
- us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL);
- if (!us->sensebuf) {
- US_DEBUGP("Sense buffer allocation failed\n");
- return -ENOMEM;
+ /* Collect the flags */
+ while (*++p && *p != ',') {
+ switch (TOLOWER(*p)) {
+ case 'a':
+ f |= US_FL_SANE_SENSE;
+ break;
+ case 'b':
+ f |= US_FL_BAD_SENSE;
+ break;
+ case 'c':
+ f |= US_FL_FIX_CAPACITY;
+ break;
+ case 'd':
+ f |= US_FL_NO_READ_DISC_INFO;
+ break;
+ case 'e':
+ f |= US_FL_NO_READ_CAPACITY_16;
+ break;
+ case 'h':
+ f |= US_FL_CAPACITY_HEURISTICS;
+ break;
+ case 'i':
+ f |= US_FL_IGNORE_DEVICE;
+ break;
+ case 'l':
+ f |= US_FL_NOT_LOCKABLE;
+ break;
+ case 'm':
+ f |= US_FL_MAX_SECTORS_64;
+ break;
+ case 'n':
+ f |= US_FL_INITIAL_READ10;
+ break;
+ case 'o':
+ f |= US_FL_CAPACITY_OK;
+ break;
+ case 'p':
+ f |= US_FL_WRITE_CACHE;
+ break;
+ case 'r':
+ f |= US_FL_IGNORE_RESIDUE;
+ break;
+ case 's':
+ f |= US_FL_SINGLE_LUN;
+ break;
+ case 'u':
+ f |= US_FL_IGNORE_UAS;
+ break;
+ case 'w':
+ f |= US_FL_NO_WP_DETECT;
+ break;
+ /* Ignore unrecognized flag characters */
+ }
}
- return 0;
+ *fflags = (*fflags & ~mask) | f;
}
+EXPORT_SYMBOL_GPL(usb_stor_adjust_quirks);
/* Get the unusual_devs entries and the string descriptors */
-static void get_device_info(struct us_data *us, int id_index)
+static int get_device_info(struct us_data *us, const struct usb_device_id *id,
+ struct us_unusual_dev *unusual_dev)
{
struct usb_device *dev = us->pusb_dev;
struct usb_interface_descriptor *idesc =
&us->pusb_intf->cur_altsetting->desc;
- struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
- struct usb_device_id *id = &storage_usb_ids[id_index];
+ struct device *pdev = &us->pusb_intf->dev;
/* Store the entries */
us->unusual_dev = unusual_dev;
- us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ?
+ us->subclass = (unusual_dev->useProtocol == USB_SC_DEVICE) ?
idesc->bInterfaceSubClass :
unusual_dev->useProtocol;
- us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
+ us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ?
idesc->bInterfaceProtocol :
unusual_dev->useTransport;
- us->flags = unusual_dev->flags;
+ us->fflags = id->driver_info;
+ usb_stor_adjust_quirks(us->pusb_dev, &us->fflags);
+
+ if (us->fflags & US_FL_IGNORE_DEVICE) {
+ dev_info(pdev, "device ignored\n");
+ return -ENODEV;
+ }
/*
* This flag is only needed when we're in high-speed, so let's
* disable it if we're in full-speed
*/
if (dev->speed != USB_SPEED_HIGH)
- us->flags &= ~US_FL_GO_SLOW;
+ us->fflags &= ~US_FL_GO_SLOW;
+
+ if (us->fflags)
+ dev_info(pdev, "Quirks match for vid %04x pid %04x: %lx\n",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct),
+ us->fflags);
/* Log a message if a non-generic unusual_dev entry contains an
* unnecessary subclass or protocol override. This may stimulate
@@ -516,181 +598,102 @@ static void get_device_info(struct us_data *us, int id_index)
* from the unusual_devs.h table.
*/
if (id->idVendor || id->idProduct) {
- static char *msgs[3] = {
+ static const char *msgs[3] = {
"an unneeded SubClass entry",
"an unneeded Protocol entry",
"unneeded SubClass and Protocol entries"};
struct usb_device_descriptor *ddesc = &dev->descriptor;
int msg = -1;
- if (unusual_dev->useProtocol != US_SC_DEVICE &&
+ if (unusual_dev->useProtocol != USB_SC_DEVICE &&
us->subclass == idesc->bInterfaceSubClass)
msg += 1;
- if (unusual_dev->useTransport != US_PR_DEVICE &&
+ if (unusual_dev->useTransport != USB_PR_DEVICE &&
us->protocol == idesc->bInterfaceProtocol)
msg += 2;
- if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE))
- printk(KERN_NOTICE USB_STORAGE "This device "
- "(%04x,%04x,%04x S %02x P %02x)"
- " has %s in unusual_devs.h\n"
- " Please send a copy of this message to "
- "<linux-usb-devel@lists.sourceforge.net>\n",
- le16_to_cpu(ddesc->idVendor),
- le16_to_cpu(ddesc->idProduct),
- le16_to_cpu(ddesc->bcdDevice),
- idesc->bInterfaceSubClass,
- idesc->bInterfaceProtocol,
- msgs[msg]);
+ if (msg >= 0 && !(us->fflags & US_FL_NEED_OVERRIDE))
+ dev_notice(pdev, "This device "
+ "(%04x,%04x,%04x S %02x P %02x)"
+ " has %s in unusual_devs.h (kernel"
+ " %s)\n"
+ " Please send a copy of this message to "
+ "<linux-usb@vger.kernel.org> and "
+ "<usb-storage@lists.one-eyed-alien.net>\n",
+ le16_to_cpu(ddesc->idVendor),
+ le16_to_cpu(ddesc->idProduct),
+ le16_to_cpu(ddesc->bcdDevice),
+ idesc->bInterfaceSubClass,
+ idesc->bInterfaceProtocol,
+ msgs[msg],
+ utsname()->release);
}
+
+ return 0;
}
/* Get the transport settings */
-static int get_transport(struct us_data *us)
+static void get_transport(struct us_data *us)
{
switch (us->protocol) {
- case US_PR_CB:
+ case USB_PR_CB:
us->transport_name = "Control/Bulk";
us->transport = usb_stor_CB_transport;
us->transport_reset = usb_stor_CB_reset;
us->max_lun = 7;
break;
- case US_PR_CBI:
+ case USB_PR_CBI:
us->transport_name = "Control/Bulk/Interrupt";
- us->transport = usb_stor_CBI_transport;
+ us->transport = usb_stor_CB_transport;
us->transport_reset = usb_stor_CB_reset;
us->max_lun = 7;
break;
- case US_PR_BULK:
+ case USB_PR_BULK:
us->transport_name = "Bulk";
us->transport = usb_stor_Bulk_transport;
us->transport_reset = usb_stor_Bulk_reset;
break;
-
-#ifdef CONFIG_USB_STORAGE_USBAT
- case US_PR_USBAT:
- us->transport_name = "Shuttle USBAT";
- us->transport = usbat_transport;
- us->transport_reset = usb_stor_CB_reset;
- us->max_lun = 1;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- case US_PR_EUSB_SDDR09:
- us->transport_name = "EUSB/SDDR09";
- us->transport = sddr09_transport;
- us->transport_reset = usb_stor_CB_reset;
- us->max_lun = 0;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_SDDR55
- case US_PR_SDDR55:
- us->transport_name = "SDDR55";
- us->transport = sddr55_transport;
- us->transport_reset = sddr55_reset;
- us->max_lun = 0;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DPCM
- case US_PR_DPCM_USB:
- us->transport_name = "Control/Bulk-EUSB/SDDR09";
- us->transport = dpcm_transport;
- us->transport_reset = usb_stor_CB_reset;
- us->max_lun = 1;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
- case US_PR_FREECOM:
- us->transport_name = "Freecom";
- us->transport = freecom_transport;
- us->transport_reset = usb_stor_freecom_reset;
- us->max_lun = 0;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
- case US_PR_DATAFAB:
- us->transport_name = "Datafab Bulk-Only";
- us->transport = datafab_transport;
- us->transport_reset = usb_stor_Bulk_reset;
- us->max_lun = 1;
- break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
- case US_PR_JUMPSHOT:
- us->transport_name = "Lexar Jumpshot Control/Bulk";
- us->transport = jumpshot_transport;
- us->transport_reset = usb_stor_Bulk_reset;
- us->max_lun = 1;
- break;
-#endif
-
- default:
- return -EIO;
}
- US_DEBUGP("Transport: %s\n", us->transport_name);
-
- /* fix for single-lun devices */
- if (us->flags & US_FL_SINGLE_LUN)
- us->max_lun = 0;
- return 0;
}
/* Get the protocol settings */
-static int get_protocol(struct us_data *us)
+static void get_protocol(struct us_data *us)
{
switch (us->subclass) {
- case US_SC_RBC:
+ case USB_SC_RBC:
us->protocol_name = "Reduced Block Commands (RBC)";
us->proto_handler = usb_stor_transparent_scsi_command;
break;
- case US_SC_8020:
+ case USB_SC_8020:
us->protocol_name = "8020i";
- us->proto_handler = usb_stor_ATAPI_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
- case US_SC_QIC:
+ case USB_SC_QIC:
us->protocol_name = "QIC-157";
- us->proto_handler = usb_stor_qic157_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
- case US_SC_8070:
+ case USB_SC_8070:
us->protocol_name = "8070i";
- us->proto_handler = usb_stor_ATAPI_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
- case US_SC_SCSI:
+ case USB_SC_SCSI:
us->protocol_name = "Transparent SCSI";
us->proto_handler = usb_stor_transparent_scsi_command;
break;
- case US_SC_UFI:
+ case USB_SC_UFI:
us->protocol_name = "Uniform Floppy Interface (UFI)";
us->proto_handler = usb_stor_ufi_command;
break;
-
-#ifdef CONFIG_USB_STORAGE_ISD200
- case US_SC_ISD200:
- us->protocol_name = "ISD200 ATA/ATAPI";
- us->proto_handler = isd200_ata_command;
- break;
-#endif
-
- default:
- return -EIO;
}
- US_DEBUGP("Protocol: %s\n", us->protocol_name);
- return 0;
}
/* Get the pipe settings */
@@ -705,33 +708,32 @@ static int get_pipes(struct us_data *us)
struct usb_endpoint_descriptor *ep_int = NULL;
/*
- * Find the endpoints we need.
+ * Find the first endpoint of each type we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
- * An optional interrupt is OK (necessary for CBI protocol).
+ * An optional interrupt-in is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
- /* Is it a BULK endpoint? */
- if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK) {
- /* BULK in or out? */
- if (ep->bEndpointAddress & USB_DIR_IN)
- ep_in = ep;
- else
- ep_out = ep;
+ if (usb_endpoint_xfer_bulk(ep)) {
+ if (usb_endpoint_dir_in(ep)) {
+ if (!ep_in)
+ ep_in = ep;
+ } else {
+ if (!ep_out)
+ ep_out = ep;
+ }
}
- /* Is it an interrupt endpoint? */
- else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT) {
- ep_int = ep;
+ else if (usb_endpoint_is_int_in(ep)) {
+ if (!ep_int)
+ ep_int = ep;
}
}
- if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) {
- US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
+ if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) {
+ usb_stor_dbg(us, "Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
@@ -739,12 +741,12 @@ static int get_pipes(struct us_data *us)
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
- ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
- us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
- ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ep_out));
+ us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
+ usb_endpoint_num(ep_in));
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
- ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ep_int));
us->ep_bInterval = ep_int->bInterval;
}
return 0;
@@ -758,7 +760,7 @@ static int usb_stor_acquire_resources(struct us_data *us)
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
- US_DEBUGP("URB allocation failed\n");
+ usb_stor_dbg(us, "URB allocation failed\n");
return -ENOMEM;
}
@@ -771,19 +773,13 @@ static int usb_stor_acquire_resources(struct us_data *us)
}
/* Start up our control thread */
- th = kthread_create(usb_stor_control_thread, us, "usb-storage");
+ th = kthread_run(usb_stor_control_thread, us, "usb-storage");
if (IS_ERR(th)) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to start control thread\n");
+ dev_warn(&us->pusb_intf->dev,
+ "Unable to start control thread\n");
return PTR_ERR(th);
}
-
- /* Take a reference to the host for the control thread and
- * count it among all the threads we have launched. Then
- * start it up. */
- scsi_host_get(us_to_host(us));
- atomic_inc(&total_threads);
- wake_up_process(th);
+ us->ctl_thread = th;
return 0;
}
@@ -791,19 +787,18 @@ static int usb_stor_acquire_resources(struct us_data *us)
/* Release all our dynamic resources */
static void usb_stor_release_resources(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
-
/* Tell the control thread to exit. The SCSI host must
- * already have been removed so it won't try to queue
- * any more commands.
+ * already have been removed and the DISCONNECTING flag set
+ * so that we won't accept any more commands.
*/
- US_DEBUGP("-- sending exit command to thread\n");
- set_bit(US_FLIDX_DISCONNECTING, &us->flags);
- up(&us->sema);
+ usb_stor_dbg(us, "-- sending exit command to thread\n");
+ complete(&us->cmnd_ready);
+ if (us->ctl_thread)
+ kthread_stop(us->ctl_thread);
/* Call the destructor routine, if it exists */
if (us->extra_destructor) {
- US_DEBUGP("-- calling extra_destructor()\n");
+ usb_stor_dbg(us, "-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
@@ -815,52 +810,48 @@ static void usb_stor_release_resources(struct us_data *us)
/* Dissociate from the USB device */
static void dissociate_dev(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __FUNCTION__);
-
- kfree(us->sensebuf);
-
- /* Free the device-related DMA-mapped buffers */
- if (us->cr)
- usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
- us->cr_dma);
- if (us->iobuf)
- usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
- us->iobuf_dma);
+ /* Free the buffers */
+ kfree(us->cr);
+ usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma);
/* Remove our private data from the interface */
usb_set_intfdata(us->pusb_intf, NULL);
}
-/* First stage of disconnect processing: stop all commands and remove
- * the host */
+/* First stage of disconnect processing: stop SCSI scanning,
+ * remove the host, and stop accepting new commands
+ */
static void quiesce_and_remove_host(struct us_data *us)
{
- /* Prevent new USB transfers, stop the current command, and
- * interrupt a SCSI-scan or device-reset delay */
- set_bit(US_FLIDX_DISCONNECTING, &us->flags);
- usb_stor_stop_transport(us);
- wake_up(&us->delay_wait);
+ struct Scsi_Host *host = us_to_host(us);
- /* It doesn't matter if the SCSI-scanning thread is still running.
- * The thread will exit when it sees the DISCONNECTING flag. */
+ /* If the device is really gone, cut short reset delays */
+ if (us->pusb_dev->state == USB_STATE_NOTATTACHED) {
+ set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+ wake_up(&us->delay_wait);
+ }
- /* Wait for the current command to finish, then remove the host */
- down(&us->dev_semaphore);
- up(&us->dev_semaphore);
+ /* Prevent SCSI scanning (if it hasn't started yet)
+ * or wait for the SCSI-scanning routine to stop.
+ */
+ cancel_delayed_work_sync(&us->scan_dwork);
- /* queuecommand won't accept any new commands and the control
- * thread won't execute a previously-queued command. If there
- * is such a command pending, complete it with an error. */
- if (us->srb) {
- us->srb->result = DID_NO_CONNECT << 16;
- scsi_lock(us_to_host(us));
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- scsi_unlock(us_to_host(us));
- }
+ /* Balance autopm calls if scanning was cancelled */
+ if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags))
+ usb_autopm_put_interface_no_suspend(us->pusb_intf);
- /* Now we own no commands so it's safe to remove the SCSI host */
- scsi_remove_host(us_to_host(us));
+ /* Removing the host will perform an orderly shutdown: caches
+ * synchronized, disks spun down, etc.
+ */
+ scsi_remove_host(host);
+
+ /* Prevent any new commands from being accepted and cut short
+ * reset delays.
+ */
+ scsi_lock(host);
+ set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+ scsi_unlock(host);
+ wake_up(&us->delay_wait);
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -874,58 +865,51 @@ static void release_everything(struct us_data *us)
scsi_host_put(us_to_host(us));
}
-/* Thread to carry out delayed SCSI-device scanning */
-static int usb_stor_scan_thread(void * __us)
+/* Delayed-work routine to carry out SCSI-device scanning */
+static void usb_stor_scan_dwork(struct work_struct *work)
{
- struct us_data *us = (struct us_data *)__us;
+ struct us_data *us = container_of(work, struct us_data,
+ scan_dwork.work);
+ struct device *dev = &us->pusb_intf->dev;
- printk(KERN_DEBUG
- "usb-storage: device found at %d\n", us->pusb_dev->devnum);
-
- /* Wait for the timeout to expire or for a disconnect */
- if (delay_use > 0) {
- printk(KERN_DEBUG "usb-storage: waiting for device "
- "to settle before scanning\n");
-retry:
- wait_event_interruptible_timeout(us->delay_wait,
- test_bit(US_FLIDX_DISCONNECTING, &us->flags),
- delay_use * HZ);
- if (try_to_freeze())
- goto retry;
+ dev_dbg(dev, "starting scan\n");
+
+ /* For bulk-only devices, determine the max LUN value */
+ if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {
+ mutex_lock(&us->dev_mutex);
+ us->max_lun = usb_stor_Bulk_max_lun(us);
+ mutex_unlock(&us->dev_mutex);
}
+ scsi_scan_host(us_to_host(us));
+ dev_dbg(dev, "scan complete\n");
- /* If the device is still connected, perform the scanning */
- if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+ /* Should we unbind if no devices were detected? */
- /* For bulk-only devices, determine the max LUN value */
- if (us->protocol == US_PR_BULK &&
- !(us->flags & US_FL_SINGLE_LUN)) {
- down(&us->dev_semaphore);
- us->max_lun = usb_stor_Bulk_max_lun(us);
- up(&us->dev_semaphore);
- }
- scsi_scan_host(us_to_host(us));
- printk(KERN_DEBUG "usb-storage: device scan complete\n");
+ usb_autopm_put_interface(us->pusb_intf);
+ clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
+}
- /* Should we unbind if no devices were detected? */
- }
+static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
- scsi_host_put(us_to_host(us));
- complete_and_exit(&threads_gone, 0);
+ if (usb_dev->bus->sg_tablesize) {
+ return usb_dev->bus->sg_tablesize;
+ }
+ return SG_ALL;
}
-
-/* Probe to see if we can drive a newly-connected USB device */
-static int storage_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+/* First part of general USB mass-storage probing */
+int usb_stor_probe1(struct us_data **pus,
+ struct usb_interface *intf,
+ const struct usb_device_id *id,
+ struct us_unusual_dev *unusual_dev)
{
struct Scsi_Host *host;
struct us_data *us;
- const int id_index = id - storage_usb_ids;
int result;
- struct task_struct *th;
- US_DEBUGP("USB Mass Storage device detected\n");
+ dev_info(&intf->dev, "USB Mass Storage device detected\n");
/*
* Ask the SCSI layer to allocate a host structure, with extra
@@ -933,162 +917,185 @@ static int storage_probe(struct usb_interface *intf,
*/
host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
if (!host) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to allocate the scsi host\n");
+ dev_warn(&intf->dev, "Unable to allocate the scsi host\n");
return -ENOMEM;
}
- us = host_to_us(host);
- memset(us, 0, sizeof(struct us_data));
- init_MUTEX(&(us->dev_semaphore));
- init_MUTEX_LOCKED(&(us->sema));
+ /*
+ * Allow 16-byte CDBs and thus > 2TB
+ */
+ host->max_cmd_len = 16;
+ host->sg_tablesize = usb_stor_sg_tablesize(intf);
+ *pus = us = host_to_us(host);
+ mutex_init(&(us->dev_mutex));
+ us_set_lock_class(&us->dev_mutex, intf);
+ init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
+ INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);
/* Associate the us_data structure with the USB device */
result = associate_dev(us, intf);
if (result)
goto BadDevice;
- /*
- * Get the unusual_devs entries and the descriptors
- *
- * id_index is calculated in the declaration to be the index number
- * of the match from the usb_device_id table, so we can find the
- * corresponding entry in the private table.
- */
- get_device_info(us, id_index);
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- if (us->protocol == US_PR_EUSB_SDDR09 ||
- us->protocol == US_PR_DPCM_USB) {
- /* set the configuration -- STALL is an acceptable response here */
- if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
- US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
- ->actconfig->desc.bConfigurationValue);
- goto BadDevice;
- }
- result = usb_reset_configuration(us->pusb_dev);
-
- US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
- if (result == -EPIPE) {
- US_DEBUGP("-- stall on control interface\n");
- } else if (result != 0) {
- /* it's not a stall, but another error -- time to bail */
- US_DEBUGP("-- Unknown error. Rejecting device\n");
- goto BadDevice;
- }
- }
-#endif
-
- /* Get the transport, protocol, and pipe settings */
- result = get_transport(us);
+ /* Get the unusual_devs entries and the descriptors */
+ result = get_device_info(us, id, unusual_dev);
if (result)
goto BadDevice;
- result = get_protocol(us);
- if (result)
+
+ /* Get standard transport and protocol settings */
+ get_transport(us);
+ get_protocol(us);
+
+ /* Give the caller a chance to fill in specialized transport
+ * or protocol settings.
+ */
+ return 0;
+
+BadDevice:
+ usb_stor_dbg(us, "storage_probe() failed\n");
+ release_everything(us);
+ return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_probe1);
+
+/* Second part of general USB mass-storage probing */
+int usb_stor_probe2(struct us_data *us)
+{
+ int result;
+ struct device *dev = &us->pusb_intf->dev;
+
+ /* Make sure the transport and protocol have both been set */
+ if (!us->transport || !us->proto_handler) {
+ result = -ENXIO;
goto BadDevice;
+ }
+ usb_stor_dbg(us, "Transport: %s\n", us->transport_name);
+ usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name);
+
+ /* fix for single-lun devices */
+ if (us->fflags & US_FL_SINGLE_LUN)
+ us->max_lun = 0;
+
+ if (!(us->fflags & US_FL_SCM_MULT_TARG))
+ us_to_host(us)->max_id = 1;
+
+ /* Find the endpoints and calculate pipe values */
result = get_pipes(us);
if (result)
goto BadDevice;
+ /*
+ * If the device returns invalid data for the first READ(10)
+ * command, indicate the command should be retried.
+ */
+ if (us->fflags & US_FL_INITIAL_READ10)
+ set_bit(US_FLIDX_REDO_READ10, &us->dflags);
+
/* Acquire all the other resources and add the host */
result = usb_stor_acquire_resources(us);
if (result)
goto BadDevice;
- result = scsi_add_host(host, &intf->dev);
+ snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
+ dev_name(&us->pusb_intf->dev));
+ result = scsi_add_host(us_to_host(us), dev);
if (result) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to add the scsi host\n");
- goto BadDevice;
- }
-
- /* Start up the thread for delayed SCSI-device scanning */
- th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
- if (IS_ERR(th)) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to start the device-scanning thread\n");
- quiesce_and_remove_host(us);
- result = PTR_ERR(th);
+ dev_warn(dev,
+ "Unable to add the scsi host\n");
goto BadDevice;
}
- /* Take a reference to the host for the scanning thread and
- * count it among all the threads we have launched. Then
- * start it up. */
- scsi_host_get(us_to_host(us));
- atomic_inc(&total_threads);
- wake_up_process(th);
+ /* Submit the delayed_work for SCSI-device scanning */
+ usb_autopm_get_interface_no_resume(us->pusb_intf);
+ set_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
+ if (delay_use > 0)
+ dev_dbg(dev, "waiting for device to settle before scanning\n");
+ queue_delayed_work(system_freezable_wq, &us->scan_dwork,
+ delay_use * HZ);
return 0;
/* We come here if there are any problems */
BadDevice:
- US_DEBUGP("storage_probe() failed\n");
+ usb_stor_dbg(us, "storage_probe() failed\n");
release_everything(us);
return result;
}
+EXPORT_SYMBOL_GPL(usb_stor_probe2);
-/* Handle a disconnect event from the USB core */
-static void storage_disconnect(struct usb_interface *intf)
+/* Handle a USB mass-storage disconnect */
+void usb_stor_disconnect(struct usb_interface *intf)
{
struct us_data *us = usb_get_intfdata(intf);
- US_DEBUGP("storage_disconnect() called\n");
quiesce_and_remove_host(us);
release_everything(us);
}
+EXPORT_SYMBOL_GPL(usb_stor_disconnect);
-/***********************************************************************
- * Initialization and registration
- ***********************************************************************/
+/* The main probe routine for standard devices */
+static int storage_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct us_unusual_dev *unusual_dev;
+ struct us_data *us;
+ int result;
+ int size;
-static struct usb_driver usb_storage_driver = {
- .owner = THIS_MODULE,
- .name = "usb-storage",
- .probe = storage_probe,
- .disconnect = storage_disconnect,
-#ifdef CONFIG_PM
- .suspend = storage_suspend,
- .resume = storage_resume,
+ /* If uas is enabled and this device can do uas then ignore it. */
+#if IS_ENABLED(CONFIG_USB_UAS)
+ if (uas_use_uas_driver(intf, id))
+ return -ENXIO;
#endif
- .id_table = storage_usb_ids,
-};
-static int __init usb_stor_init(void)
-{
- int retval;
- printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
+ /*
+ * If the device isn't standard (is handled by a subdriver
+ * module) then don't accept it.
+ */
+ if (usb_usual_ignore_device(intf))
+ return -ENXIO;
+
+ /*
+ * Call the general probe procedures.
+ *
+ * The unusual_dev_list array is parallel to the usb_storage_usb_ids
+ * table, so we use the index of the id entry to find the
+ * corresponding unusual_devs entry.
+ */
- /* register the driver, return usb_register return code if error */
- retval = usb_register(&usb_storage_driver);
- if (retval == 0)
- printk(KERN_INFO "USB Mass Storage support registered.\n");
+ size = ARRAY_SIZE(us_unusual_dev_list);
+ if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+ unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+ } else {
+ unusual_dev = &for_dynamic_ids;
- return retval;
-}
+ dev_dbg(&intf->dev, "Use Bulk-Only transport with the Transparent SCSI protocol for dynamic id: 0x%04x 0x%04x\n",
+ id->idVendor, id->idProduct);
+ }
-static void __exit usb_stor_exit(void)
-{
- US_DEBUGP("usb_stor_exit() called\n");
+ result = usb_stor_probe1(&us, intf, id, unusual_dev);
+ if (result)
+ return result;
- /* Deregister the driver
- * This will cause disconnect() to be called for each
- * attached unit
- */
- US_DEBUGP("-- calling usb_deregister()\n");
- usb_deregister(&usb_storage_driver) ;
+ /* No special transport or protocol settings in the main module */
- /* Don't return until all of our control and scanning threads
- * have exited. Since each thread signals threads_gone as its
- * last act, we have to call wait_for_completion the right number
- * of times.
- */
- while (atomic_read(&total_threads) > 0) {
- wait_for_completion(&threads_gone);
- atomic_dec(&total_threads);
- }
+ result = usb_stor_probe2(us);
+ return result;
}
-module_init(usb_stor_init);
-module_exit(usb_stor_exit);
+static struct usb_driver usb_storage_driver = {
+ .name = "usb-storage",
+ .probe = storage_probe,
+ .disconnect = usb_stor_disconnect,
+ .suspend = usb_stor_suspend,
+ .resume = usb_stor_resume,
+ .reset_resume = usb_stor_reset_resume,
+ .pre_reset = usb_stor_pre_reset,
+ .post_reset = usb_stor_post_reset,
+ .id_table = usb_storage_usb_ids,
+ .supports_autosuspend = 1,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(usb_storage_driver);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 98b09711a73..307e339a947 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -1,8 +1,6 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
- * $Id: usb.h,v 1.21 2002/04/21 02:57:59 mdharm Exp $
- *
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
@@ -45,9 +43,11 @@
#define _USB_H_
#include <linux/usb.h>
+#include <linux/usb_usual.h>
#include <linux/blkdev.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <scsi/scsi_host.h>
struct us_data;
@@ -63,49 +63,19 @@ struct us_unusual_dev {
__u8 useProtocol;
__u8 useTransport;
int (*initFunction)(struct us_data *);
- unsigned int flags;
};
-/*
- * Static flag definitions. We use this roundabout technique so that the
- * proc_info() routine can automatically display a message for each flag.
- */
-#define US_DO_ALL_FLAGS \
- US_FLAG(SINGLE_LUN, 0x00000001) \
- /* allow access to only LUN 0 */ \
- US_FLAG(NEED_OVERRIDE, 0x00000002) \
- /* unusual_devs entry is necessary */ \
- US_FLAG(SCM_MULT_TARG, 0x00000004) \
- /* supports multiple targets */ \
- US_FLAG(FIX_INQUIRY, 0x00000008) \
- /* INQUIRY response needs faking */ \
- US_FLAG(FIX_CAPACITY, 0x00000010) \
- /* READ CAPACITY response too big */ \
- US_FLAG(IGNORE_RESIDUE, 0x00000020) \
- /* reported residue is wrong */ \
- US_FLAG(BULK32, 0x00000040) \
- /* Uses 32-byte CBW length */ \
- US_FLAG(NOT_LOCKABLE, 0x00000080) \
- /* PREVENT/ALLOW not supported */ \
- US_FLAG(GO_SLOW, 0x00000100) \
- /* Need delay after Command phase */ \
- US_FLAG(NO_WP_DETECT, 0x00000200) \
- /* Don't check for write-protect */ \
-
-#define US_FLAG(name, value) US_FL_##name = value ,
-enum { US_DO_ALL_FLAGS };
-#undef US_FLAG
-
-/* Dynamic flag definitions: used in set_bit() etc. */
-#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */
-#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */
-#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */
-#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */
-#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \
- (1UL << US_FLIDX_DISCONNECTING))
-#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */
-#define US_FLIDX_TIMED_OUT 23 /* 0x00800000 SCSI midlayer timed out */
+/* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */
+#define US_FLIDX_URB_ACTIVE 0 /* current_urb is in use */
+#define US_FLIDX_SG_ACTIVE 1 /* current_sg is in use */
+#define US_FLIDX_ABORTING 2 /* abort is in progress */
+#define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */
+#define US_FLIDX_RESETTING 4 /* device reset in progress */
+#define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
+#define US_FLIDX_SCAN_PENDING 6 /* scanning not yet done */
+#define US_FLIDX_REDO_READ10 7 /* redo READ(10) command */
+#define US_FLIDX_READ10_WORKED 8 /* previous READ(10) succeeded */
#define USB_STOR_STRING_LEN 32
@@ -122,19 +92,24 @@ enum { US_DO_ALL_FLAGS };
typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*);
typedef int (*trans_reset)(struct us_data*);
typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*);
-typedef void (*extra_data_destructor)(void *); /* extra data destructor */
+typedef void (*extra_data_destructor)(void *); /* extra data destructor */
+typedef void (*pm_hook)(struct us_data *, int); /* power management hook */
+
+#define US_SUSPEND 0
+#define US_RESUME 1
/* we allocate one of these for every device that we remember */
struct us_data {
/* The device we're working with
* It's important to note:
- * (o) you must hold dev_semaphore to change pusb_dev
+ * (o) you must hold dev_mutex to change pusb_dev
*/
- struct semaphore dev_semaphore; /* protect pusb_dev */
+ struct mutex dev_mutex; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
struct usb_interface *pusb_intf; /* this interface */
struct us_unusual_dev *unusual_dev; /* device-filter entry */
- unsigned long flags; /* from filter initially */
+ unsigned long fflags; /* fixed flags from filter */
+ unsigned long dflags; /* dynamic atomic bitflags */
unsigned int send_bulk_pipe; /* cached pipe values */
unsigned int recv_bulk_pipe;
unsigned int send_ctrl_pipe;
@@ -160,31 +135,39 @@ struct us_data {
/* SCSI interfaces */
struct scsi_cmnd *srb; /* current srb */
unsigned int tag; /* current dCBWTag */
+ char scsi_name[32]; /* scsi_host name */
/* control and bulk communications data */
struct urb *current_urb; /* USB requests */
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
- unsigned char *sensebuf; /* sense data buffer */
- dma_addr_t cr_dma; /* buffer DMA addresses */
- dma_addr_t iobuf_dma;
+ dma_addr_t iobuf_dma; /* buffer DMA addresses */
+ struct task_struct *ctl_thread; /* the control thread */
/* mutual exclusion and synchronization structures */
- struct semaphore sema; /* to sleep thread on */
+ struct completion cmnd_ready; /* to sleep thread on */
struct completion notify; /* thread begin/end */
- wait_queue_head_t delay_wait; /* wait during scan, reset */
+ wait_queue_head_t delay_wait; /* wait during reset */
+ struct delayed_work scan_dwork; /* for async scanning */
/* subdriver information */
void *extra; /* Any extra data */
extra_data_destructor extra_destructor;/* extra data destructor */
+#ifdef CONFIG_PM
+ pm_hook suspend_resume_hook;
+#endif
+
+ /* hacks for READ CAPACITY bug handling */
+ int use_last_sector_hacks;
+ int last_sector_retries;
};
/* Convert between us_data and the corresponding Scsi_Host */
-static struct Scsi_Host inline *us_to_host(struct us_data *us) {
+static inline struct Scsi_Host *us_to_host(struct us_data *us) {
return container_of((void *) us, struct Scsi_Host, hostdata);
}
-static struct us_data inline *host_to_us(struct Scsi_Host *host) {
+static inline struct us_data *host_to_us(struct Scsi_Host *host) {
return (struct us_data *) host->hostdata;
}
@@ -197,8 +180,28 @@ extern void fill_inquiry_response(struct us_data *us,
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
+/* General routines provided by the usb-storage standard core */
+#ifdef CONFIG_PM
+extern int usb_stor_suspend(struct usb_interface *iface, pm_message_t message);
+extern int usb_stor_resume(struct usb_interface *iface);
+extern int usb_stor_reset_resume(struct usb_interface *iface);
+#else
+#define usb_stor_suspend NULL
+#define usb_stor_resume NULL
+#define usb_stor_reset_resume NULL
+#endif
+
+extern int usb_stor_pre_reset(struct usb_interface *iface);
+extern int usb_stor_post_reset(struct usb_interface *iface);
+
+extern int usb_stor_probe1(struct us_data **pus,
+ struct usb_interface *intf,
+ const struct usb_device_id *id,
+ struct us_unusual_dev *unusual_dev);
+extern int usb_stor_probe2(struct us_data *us);
+extern void usb_stor_disconnect(struct usb_interface *intf);
-/* Vendor ID list for devices that require special handling */
-#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */
+extern void usb_stor_adjust_quirks(struct usb_device *dev,
+ unsigned long *fflags);
#endif
diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c
new file mode 100644
index 00000000000..5ef8ce74aae
--- /dev/null
+++ b/drivers/usb/storage/usual-tables.c
@@ -0,0 +1,123 @@
+/* Driver for USB Mass Storage devices
+ * Usual Tables File for usb-storage and libusual
+ *
+ * Copyright (C) 2009 Alan Stern (stern@rowland.harvard.edu)
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+
+
+/*
+ * The table of devices
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
+#define COMPLIANT_DEV UNUSUAL_DEV
+
+#define USUAL_DEV(useProto, useTrans) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }
+
+/* Define the device is matched with Vendor ID and interface descriptors */
+#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+ | USB_DEVICE_ID_MATCH_VENDOR, \
+ .idVendor = (id_vendor), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr), \
+ .driver_info = (flags) \
+}
+
+struct usb_device_id usb_storage_usb_ids[] = {
+# include "unusual_devs.h"
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);
+
+#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
+#undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
+
+/*
+ * The table of devices to ignore
+ */
+struct ignore_entry {
+ u16 vid, pid, bcdmin, bcdmax;
+};
+
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ \
+ .vid = id_vendor, \
+ .pid = id_product, \
+ .bcdmin = bcdDeviceMin, \
+ .bcdmax = bcdDeviceMax, \
+}
+
+static struct ignore_entry ignore_ids[] = {
+# include "unusual_alauda.h"
+# include "unusual_cypress.h"
+# include "unusual_datafab.h"
+# include "unusual_ene_ub6250.h"
+# include "unusual_freecom.h"
+# include "unusual_isd200.h"
+# include "unusual_jumpshot.h"
+# include "unusual_karma.h"
+# include "unusual_onetouch.h"
+# include "unusual_realtek.h"
+# include "unusual_sddr09.h"
+# include "unusual_sddr55.h"
+# include "unusual_usbat.h"
+ { } /* Terminating entry */
+};
+
+#undef UNUSUAL_DEV
+
+/* Return an error if a device is in the ignore_ids list */
+int usb_usual_ignore_device(struct usb_interface *intf)
+{
+ struct usb_device *udev;
+ unsigned vid, pid, bcd;
+ struct ignore_entry *p;
+
+ udev = interface_to_usbdev(intf);
+ vid = le16_to_cpu(udev->descriptor.idVendor);
+ pid = le16_to_cpu(udev->descriptor.idProduct);
+ bcd = le16_to_cpu(udev->descriptor.bcdDevice);
+
+ for (p = ignore_ids; p->vid; ++p) {
+ if (p->vid == vid && p->pid == pid &&
+ p->bcdmin <= bcd && p->bcdmax >= bcd)
+ return -ENXIO;
+ }
+ return 0;
+}