mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
214
drivers/usb/storage/Kconfig
Normal file
214
drivers/usb/storage/Kconfig
Normal file
|
@ -0,0 +1,214 @@
|
|||
#
|
||||
# USB Storage driver configuration
|
||||
#
|
||||
|
||||
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 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
|
||||
floppy drives, USB hard disks, USB tape drives, USB CD-ROMs,
|
||||
USB flash devices, and memory sticks, along with
|
||||
similar devices. This driver may also be used for some cameras
|
||||
and card readers.
|
||||
|
||||
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 usb-storage.
|
||||
|
||||
config USB_STORAGE_DEBUG
|
||||
bool "USB Mass Storage verbose debug"
|
||||
depends on USB_STORAGE
|
||||
help
|
||||
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
|
||||
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.datafab.com/>.
|
||||
|
||||
If this driver is compiled as a module, it will be named ums-datafab.
|
||||
|
||||
config USB_STORAGE_FREECOM
|
||||
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
|
||||
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.
|
||||
|
||||
Some of the products that use this chip are:
|
||||
|
||||
- Archos Jukebox 6000
|
||||
- ISD SmartCable for Storage
|
||||
- Taiwan Skymaster CD530U/DEL-0241 IDE bridge
|
||||
- Sony CRX10U CD-R/RW drive
|
||||
- CyQ've CQ8060A CDRW drive
|
||||
- Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
|
||||
|
||||
If this driver is compiled as a module, it will be named ums-isd200.
|
||||
|
||||
config USB_STORAGE_USBAT
|
||||
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.
|
||||
|
||||
Devices reported to work with this driver include:
|
||||
- CompactFlash reader included with Kodak DC3800 camera
|
||||
- Dane-Elec Zmate CompactFlash reader
|
||||
- Delkin Efilm reader2
|
||||
- HP 8200e/8210e/8230e CD-Writer Plus drives
|
||||
- I-JAM JS-50U
|
||||
- Jessops CompactFlash JESDCFRU BLACK
|
||||
- Kingston Technology PCREAD-USB/CF
|
||||
- Maxell UA4 CompactFlash reader
|
||||
- Memorex UCF-100
|
||||
- Microtech ZiO! ICS-45 CF2
|
||||
- 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
|
||||
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! CompactFlash/SmartMedia reader.
|
||||
|
||||
If this driver is compiled as a module, it will be named ums-sddr09.
|
||||
|
||||
config USB_STORAGE_SDDR55
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
This code registers the button on the front of Maxtor OneTouch USB
|
||||
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.
|
||||
Note that this driver does not support SM cards.
|
||||
|
||||
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.
|
44
drivers/usb/storage/Makefile
Normal file
44
drivers/usb/storage/Makefile
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Makefile for the USB Mass Storage device drivers.
|
||||
#
|
||||
# 15 Aug 2000, Christoph Hellwig <hch@infradead.org>
|
||||
# Rewritten to use lists instead of if-statements.
|
||||
#
|
||||
|
||||
ccflags-y := -Idrivers/scsi
|
||||
|
||||
obj-$(CONFIG_USB_UAS) += uas.o
|
||||
obj-$(CONFIG_USB_STORAGE) += usb-storage.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
|
||||
|
||||
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
|
1264
drivers/usb/storage/alauda.c
Normal file
1264
drivers/usb/storage/alauda.c
Normal file
File diff suppressed because it is too large
Load diff
290
drivers/usb/storage/cypress_atacb.c
Normal file
290
drivers/usb/storage/cypress_atacb.c
Normal file
|
@ -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);
|
758
drivers/usb/storage/datafab.c
Normal file
758
drivers/usb/storage/datafab.c
Normal file
|
@ -0,0 +1,758 @@
|
|||
/* Driver for Datafab USB Compact Flash reader
|
||||
*
|
||||
* datafab driver v0.1:
|
||||
*
|
||||
* First release
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
|
||||
*
|
||||
* Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
|
||||
* which I used as a template for this driver.
|
||||
*
|
||||
* Some bugfixes and scatter-gather code by Gregory P. Smith
|
||||
* (greg-usb@electricrain.com)
|
||||
*
|
||||
* Fix for media change by Joerg Schneider (js@joergschneider.com)
|
||||
*
|
||||
* Other contributors:
|
||||
* (c) 2002 Alan Stern <stern@rowland.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This driver attempts to support USB CompactFlash reader/writer devices
|
||||
* based on Datafab USB-to-ATA chips. It was specifically developed for the
|
||||
* Datafab MDCFE-B USB CompactFlash reader but has since been found to work
|
||||
* with a variety of Datafab-based devices from a number of manufacturers.
|
||||
* I've received a report of this driver working with a Datafab-based
|
||||
* SmartMedia device though please be aware that I'm personally unable to
|
||||
* test SmartMedia support.
|
||||
*
|
||||
* This driver supports reading and writing. If you're truly paranoid,
|
||||
* however, you can force the driver into a write-protected state by setting
|
||||
* the WP enable bits in datafab_handle_mode_sense(). See the comments
|
||||
* in that routine.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "transport.h"
|
||||
#include "protocol.h"
|
||||
#include "debug.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;
|
||||
|
||||
usb_stor_dbg(us, "len = %d\n", len);
|
||||
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
|
||||
data, len, NULL);
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
|
||||
if (len == 0)
|
||||
return USB_STOR_XFER_GOOD;
|
||||
|
||||
usb_stor_dbg(us, "len = %d\n", len);
|
||||
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
|
||||
data, len, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int datafab_read_data(struct us_data *us,
|
||||
struct datafab_info *info,
|
||||
u32 sector,
|
||||
u32 sectors)
|
||||
{
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *buffer;
|
||||
unsigned char thistime;
|
||||
unsigned int totallen, alloclen;
|
||||
int len, result;
|
||||
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
|
||||
// supports beyond 24-bit addressing. It's kind of hard to test
|
||||
// since it requires > 8GB CF card.
|
||||
//
|
||||
if (sectors > 0x0FFFFFFF)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
if (info->lun == -1) {
|
||||
result = datafab_determine_lun(us, info);
|
||||
if (result != USB_STOR_TRANSPORT_GOOD)
|
||||
return result;
|
||||
}
|
||||
|
||||
totallen = sectors * info->ssize;
|
||||
|
||||
// Since we don't read more than 64 KB 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.
|
||||
|
||||
alloclen = min(totallen, 65536u);
|
||||
buffer = kmalloc(alloclen, GFP_NOIO);
|
||||
if (buffer == NULL)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
do {
|
||||
// loop, never allocate or transfer more than 64k at once
|
||||
// (min(128k, 255*info->ssize) is the real limit)
|
||||
|
||||
len = min(totallen, alloclen);
|
||||
thistime = (len / info->ssize) & 0xff;
|
||||
|
||||
command[0] = 0;
|
||||
command[1] = thistime;
|
||||
command[2] = sector & 0xFF;
|
||||
command[3] = (sector >> 8) & 0xFF;
|
||||
command[4] = (sector >> 16) & 0xFF;
|
||||
|
||||
command[5] = 0xE0 + (info->lun << 4);
|
||||
command[5] |= (sector >> 24) & 0x0F;
|
||||
command[6] = 0x20;
|
||||
command[7] = 0x01;
|
||||
|
||||
// send the read command
|
||||
result = datafab_bulk_write(us, command, 8);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// read the result
|
||||
result = datafab_bulk_read(us, buffer, len);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// Store the data in the transfer buffer
|
||||
usb_stor_access_xfer_buf(buffer, len, us->srb,
|
||||
&sg, &sg_offset, TO_XFER_BUF);
|
||||
|
||||
sector += thistime;
|
||||
totallen -= len;
|
||||
} while (totallen > 0);
|
||||
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
|
||||
leave:
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int datafab_write_data(struct us_data *us,
|
||||
struct datafab_info *info,
|
||||
u32 sector,
|
||||
u32 sectors)
|
||||
{
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *reply = us->iobuf;
|
||||
unsigned char *buffer;
|
||||
unsigned char thistime;
|
||||
unsigned int totallen, alloclen;
|
||||
int len, result;
|
||||
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
|
||||
// supports beyond 24-bit addressing. It's kind of hard to test
|
||||
// since it requires > 8GB CF card.
|
||||
//
|
||||
if (sectors > 0x0FFFFFFF)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
if (info->lun == -1) {
|
||||
result = datafab_determine_lun(us, info);
|
||||
if (result != USB_STOR_TRANSPORT_GOOD)
|
||||
return result;
|
||||
}
|
||||
|
||||
totallen = sectors * info->ssize;
|
||||
|
||||
// Since we don't write more than 64 KB 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.
|
||||
|
||||
alloclen = min(totallen, 65536u);
|
||||
buffer = kmalloc(alloclen, GFP_NOIO);
|
||||
if (buffer == NULL)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
do {
|
||||
// loop, never allocate or transfer more than 64k at once
|
||||
// (min(128k, 255*info->ssize) is the real limit)
|
||||
|
||||
len = min(totallen, alloclen);
|
||||
thistime = (len / info->ssize) & 0xff;
|
||||
|
||||
// Get the data from the transfer buffer
|
||||
usb_stor_access_xfer_buf(buffer, len, us->srb,
|
||||
&sg, &sg_offset, FROM_XFER_BUF);
|
||||
|
||||
command[0] = 0;
|
||||
command[1] = thistime;
|
||||
command[2] = sector & 0xFF;
|
||||
command[3] = (sector >> 8) & 0xFF;
|
||||
command[4] = (sector >> 16) & 0xFF;
|
||||
|
||||
command[5] = 0xE0 + (info->lun << 4);
|
||||
command[5] |= (sector >> 24) & 0x0F;
|
||||
command[6] = 0x30;
|
||||
command[7] = 0x02;
|
||||
|
||||
// send the command
|
||||
result = datafab_bulk_write(us, command, 8);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// send the data
|
||||
result = datafab_bulk_write(us, buffer, len);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// read the result
|
||||
result = datafab_bulk_read(us, reply, 2);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
if (reply[0] != 0x50 && reply[1] != 0) {
|
||||
usb_stor_dbg(us, "Gah! write return code: %02x %02x\n",
|
||||
reply[0], reply[1]);
|
||||
result = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
sector += thistime;
|
||||
totallen -= len;
|
||||
} while (totallen > 0);
|
||||
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
|
||||
leave:
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int datafab_determine_lun(struct us_data *us,
|
||||
struct datafab_info *info)
|
||||
{
|
||||
// Dual-slot readers can be thought of as dual-LUN devices.
|
||||
// We need to determine which card slot is being used.
|
||||
// We'll send an IDENTIFY DEVICE command and see which LUN responds...
|
||||
//
|
||||
// There might be a better way of doing this?
|
||||
|
||||
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *buf;
|
||||
int count = 0, rc;
|
||||
|
||||
if (!info)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
memcpy(command, scommand, 8);
|
||||
buf = kmalloc(512, GFP_NOIO);
|
||||
if (!buf)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
usb_stor_dbg(us, "locating...\n");
|
||||
|
||||
// we'll try 3 times before giving up...
|
||||
//
|
||||
while (count++ < 3) {
|
||||
command[5] = 0xa0;
|
||||
|
||||
rc = datafab_bulk_write(us, command, 8);
|
||||
if (rc != USB_STOR_XFER_GOOD) {
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = datafab_bulk_read(us, buf, 512);
|
||||
if (rc == USB_STOR_XFER_GOOD) {
|
||||
info->lun = 0;
|
||||
rc = USB_STOR_TRANSPORT_GOOD;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
command[5] = 0xb0;
|
||||
|
||||
rc = datafab_bulk_write(us, command, 8);
|
||||
if (rc != USB_STOR_XFER_GOOD) {
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = datafab_bulk_read(us, buf, 512);
|
||||
if (rc == USB_STOR_XFER_GOOD) {
|
||||
info->lun = 1;
|
||||
rc = USB_STOR_TRANSPORT_GOOD;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
leave:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int datafab_id_device(struct us_data *us,
|
||||
struct datafab_info *info)
|
||||
{
|
||||
// this is a variation of the ATA "IDENTIFY DEVICE" command...according
|
||||
// to the ATA spec, 'Sector Count' isn't used but the Windows driver
|
||||
// sets this bit so we do too...
|
||||
//
|
||||
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *reply;
|
||||
int rc;
|
||||
|
||||
if (!info)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
if (info->lun == -1) {
|
||||
rc = datafab_determine_lun(us, info);
|
||||
if (rc != USB_STOR_TRANSPORT_GOOD)
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(command, scommand, 8);
|
||||
reply = kmalloc(512, GFP_NOIO);
|
||||
if (!reply)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
command[5] += (info->lun << 4);
|
||||
|
||||
rc = datafab_bulk_write(us, command, 8);
|
||||
if (rc != USB_STOR_XFER_GOOD) {
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
// we'll go ahead and extract the media capacity while we're here...
|
||||
//
|
||||
rc = datafab_bulk_read(us, reply, 512);
|
||||
if (rc == USB_STOR_XFER_GOOD) {
|
||||
// capacity is at word offset 57-58
|
||||
//
|
||||
info->sectors = ((u32)(reply[117]) << 24) |
|
||||
((u32)(reply[116]) << 16) |
|
||||
((u32)(reply[115]) << 8) |
|
||||
((u32)(reply[114]) );
|
||||
rc = USB_STOR_TRANSPORT_GOOD;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
leave:
|
||||
kfree(reply);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int datafab_handle_mode_sense(struct us_data *us,
|
||||
struct scsi_cmnd * srb,
|
||||
int sense_6)
|
||||
{
|
||||
static unsigned char rw_err_page[12] = {
|
||||
0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
|
||||
};
|
||||
static unsigned char cache_page[12] = {
|
||||
0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static unsigned char rbac_page[12] = {
|
||||
0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static unsigned char timer_page[8] = {
|
||||
0x1C, 0x6, 0, 0, 0, 0
|
||||
};
|
||||
unsigned char pc, page_code;
|
||||
unsigned int i = 0;
|
||||
struct datafab_info *info = (struct datafab_info *) (us->extra);
|
||||
unsigned char *ptr = us->iobuf;
|
||||
|
||||
// most of this stuff is just a hack to get things working. the
|
||||
// datafab reader doesn't present a SCSI interface so we
|
||||
// fudge the SCSI commands...
|
||||
//
|
||||
|
||||
pc = srb->cmnd[2] >> 6;
|
||||
page_code = srb->cmnd[2] & 0x3F;
|
||||
|
||||
switch (pc) {
|
||||
case 0x0:
|
||||
usb_stor_dbg(us, "Current values\n");
|
||||
break;
|
||||
case 0x1:
|
||||
usb_stor_dbg(us, "Changeable values\n");
|
||||
break;
|
||||
case 0x2:
|
||||
usb_stor_dbg(us, "Default values\n");
|
||||
break;
|
||||
case 0x3:
|
||||
usb_stor_dbg(us, "Saves values\n");
|
||||
break;
|
||||
}
|
||||
|
||||
memset(ptr, 0, 8);
|
||||
if (sense_6) {
|
||||
ptr[2] = 0x00; // WP enable: 0x80
|
||||
i = 4;
|
||||
} else {
|
||||
ptr[3] = 0x00; // WP enable: 0x80
|
||||
i = 8;
|
||||
}
|
||||
|
||||
switch (page_code) {
|
||||
default:
|
||||
// vendor-specific mode
|
||||
info->sense_key = 0x05;
|
||||
info->sense_asc = 0x24;
|
||||
info->sense_ascq = 0x00;
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
|
||||
case 0x1:
|
||||
memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
|
||||
i += sizeof(rw_err_page);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
memcpy(ptr + i, cache_page, sizeof(cache_page));
|
||||
i += sizeof(cache_page);
|
||||
break;
|
||||
|
||||
case 0x1B:
|
||||
memcpy(ptr + i, rbac_page, sizeof(rbac_page));
|
||||
i += sizeof(rbac_page);
|
||||
break;
|
||||
|
||||
case 0x1C:
|
||||
memcpy(ptr + i, timer_page, sizeof(timer_page));
|
||||
i += sizeof(timer_page);
|
||||
break;
|
||||
|
||||
case 0x3F: // retrieve all pages
|
||||
memcpy(ptr + i, timer_page, sizeof(timer_page));
|
||||
i += sizeof(timer_page);
|
||||
memcpy(ptr + i, rbac_page, sizeof(rbac_page));
|
||||
i += sizeof(rbac_page);
|
||||
memcpy(ptr + i, cache_page, sizeof(cache_page));
|
||||
i += sizeof(cache_page);
|
||||
memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
|
||||
i += sizeof(rw_err_page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sense_6)
|
||||
ptr[0] = i - 1;
|
||||
else
|
||||
((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
|
||||
usb_stor_set_xfer_buf(ptr, i, srb);
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
static void datafab_info_destructor(void *extra)
|
||||
{
|
||||
// this routine is a placeholder...
|
||||
// currently, we don't allocate any extra memory so we're okay
|
||||
}
|
||||
|
||||
|
||||
// Transport for the Datafab MDCFE-B
|
||||
//
|
||||
static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
|
||||
{
|
||||
struct datafab_info *info;
|
||||
int rc;
|
||||
unsigned long block, blocks;
|
||||
unsigned char *ptr = us->iobuf;
|
||||
static unsigned char inquiry_reply[8] = {
|
||||
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
if (!us->extra) {
|
||||
us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
|
||||
if (!us->extra)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
us->extra_destructor = datafab_info_destructor;
|
||||
((struct datafab_info *)us->extra)->lun = -1;
|
||||
}
|
||||
|
||||
info = (struct datafab_info *) (us->extra);
|
||||
|
||||
if (srb->cmnd[0] == INQUIRY) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == READ_CAPACITY) {
|
||||
info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec
|
||||
rc = datafab_id_device(us, info);
|
||||
if (rc != USB_STOR_TRANSPORT_GOOD)
|
||||
return rc;
|
||||
|
||||
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
|
||||
((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
|
||||
((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
|
||||
usb_stor_set_xfer_buf(ptr, 8, srb);
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == MODE_SELECT_10) {
|
||||
usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
// don't bother implementing READ_6 or WRITE_6.
|
||||
//
|
||||
if (srb->cmnd[0] == READ_10) {
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
|
||||
|
||||
usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return datafab_read_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == READ_12) {
|
||||
// we'll probably never see a READ_12 but we'll do it anyway...
|
||||
//
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
|
||||
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
|
||||
|
||||
usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return datafab_read_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == WRITE_10) {
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
|
||||
|
||||
usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return datafab_write_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == WRITE_12) {
|
||||
// we'll probably never see a WRITE_12 but we'll do it anyway...
|
||||
//
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
|
||||
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
|
||||
|
||||
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) {
|
||||
usb_stor_dbg(us, "TEST_UNIT_READY\n");
|
||||
return datafab_id_device(us, info);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == REQUEST_SENSE) {
|
||||
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
|
||||
// necessary
|
||||
//
|
||||
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] == MODE_SENSE) {
|
||||
usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
|
||||
return datafab_handle_mode_sense(us, srb, 1);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == MODE_SENSE_10) {
|
||||
usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
|
||||
return datafab_handle_mode_sense(us, srb, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == START_STOP) {
|
||||
/* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
media change */
|
||||
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);
|
||||
if (rc == USB_STOR_TRANSPORT_GOOD) {
|
||||
info->sense_key = NO_SENSE;
|
||||
srb->result = SUCCESS;
|
||||
} else {
|
||||
info->sense_key = UNIT_ATTENTION;
|
||||
srb->result = SAM_STAT_CHECK_CONDITION;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
195
drivers/usb/storage/debug.c
Normal file
195
drivers/usb/storage/debug.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* Debugging Functions Source Code File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* Developed with the assistance of:
|
||||
* (c) 2002 Alan Stern <stern@rowland.org>
|
||||
*
|
||||
* Initial work by:
|
||||
* (c) 1999 Michael Gee (michael@linuxspecific.com)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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/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(const struct us_data *us, struct scsi_cmnd *srb)
|
||||
{
|
||||
char *what = NULL;
|
||||
int i;
|
||||
|
||||
switch (srb->cmnd[0]) {
|
||||
case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
|
||||
case REZERO_UNIT: what = "REZERO_UNIT"; break;
|
||||
case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
|
||||
case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
|
||||
case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
|
||||
case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
|
||||
case READ_6: what = "READ_6"; break;
|
||||
case WRITE_6: what = "WRITE_6"; break;
|
||||
case SEEK_6: what = "SEEK_6"; break;
|
||||
case READ_REVERSE: what = "READ_REVERSE"; break;
|
||||
case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
|
||||
case SPACE: what = "SPACE"; break;
|
||||
case INQUIRY: what = "INQUIRY"; break;
|
||||
case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
|
||||
case MODE_SELECT: what = "MODE_SELECT"; break;
|
||||
case RESERVE: what = "RESERVE"; break;
|
||||
case RELEASE: what = "RELEASE"; break;
|
||||
case COPY: what = "COPY"; break;
|
||||
case ERASE: what = "ERASE"; break;
|
||||
case MODE_SENSE: what = "MODE_SENSE"; break;
|
||||
case START_STOP: what = "START_STOP"; break;
|
||||
case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
|
||||
case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
|
||||
case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
|
||||
case SET_WINDOW: what = "SET_WINDOW"; break;
|
||||
case READ_CAPACITY: what = "READ_CAPACITY"; break;
|
||||
case READ_10: what = "READ_10"; break;
|
||||
case WRITE_10: what = "WRITE_10"; break;
|
||||
case SEEK_10: what = "SEEK_10"; break;
|
||||
case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
|
||||
case VERIFY: what = "VERIFY"; break;
|
||||
case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
|
||||
case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
|
||||
case SEARCH_LOW: what = "SEARCH_LOW"; break;
|
||||
case SET_LIMITS: what = "SET_LIMITS"; break;
|
||||
case READ_POSITION: what = "READ_POSITION"; break;
|
||||
case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
|
||||
case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
|
||||
case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
|
||||
case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
|
||||
case COMPARE: what = "COMPARE"; break;
|
||||
case COPY_VERIFY: what = "COPY_VERIFY"; break;
|
||||
case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
|
||||
case READ_BUFFER: what = "READ_BUFFER"; break;
|
||||
case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
|
||||
case READ_LONG: what = "READ_LONG"; break;
|
||||
case WRITE_LONG: what = "WRITE_LONG"; break;
|
||||
case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
|
||||
case WRITE_SAME: what = "WRITE_SAME"; break;
|
||||
case GPCMD_READ_SUBCHANNEL: what = "READ SUBCHANNEL"; break;
|
||||
case READ_TOC: what = "READ_TOC"; break;
|
||||
case GPCMD_READ_HEADER: what = "READ HEADER"; break;
|
||||
case GPCMD_PLAY_AUDIO_10: what = "PLAY AUDIO (10)"; break;
|
||||
case GPCMD_PLAY_AUDIO_MSF: what = "PLAY AUDIO MSF"; break;
|
||||
case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
|
||||
what = "GET EVENT/STATUS NOTIFICATION"; break;
|
||||
case GPCMD_PAUSE_RESUME: what = "PAUSE/RESUME"; break;
|
||||
case LOG_SELECT: what = "LOG_SELECT"; break;
|
||||
case LOG_SENSE: what = "LOG_SENSE"; break;
|
||||
case GPCMD_STOP_PLAY_SCAN: what = "STOP PLAY/SCAN"; break;
|
||||
case GPCMD_READ_DISC_INFO: what = "READ DISC INFORMATION"; break;
|
||||
case GPCMD_READ_TRACK_RZONE_INFO:
|
||||
what = "READ TRACK INFORMATION"; break;
|
||||
case GPCMD_RESERVE_RZONE_TRACK: what = "RESERVE TRACK"; break;
|
||||
case GPCMD_SEND_OPC: what = "SEND OPC"; break;
|
||||
case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
|
||||
case GPCMD_REPAIR_RZONE_TRACK: what = "REPAIR TRACK"; break;
|
||||
case 0x59: what = "READ MASTER CUE"; break;
|
||||
case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
|
||||
case GPCMD_CLOSE_TRACK: what = "CLOSE TRACK/SESSION"; break;
|
||||
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;
|
||||
case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
|
||||
case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
|
||||
case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
|
||||
case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
|
||||
case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
|
||||
case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
|
||||
case GPCMD_READ_CD_MSF: what = "READ CD MSF"; break;
|
||||
case GPCMD_SCAN: what = "SCAN"; break;
|
||||
case GPCMD_SET_SPEED: what = "SET CD SPEED"; break;
|
||||
case GPCMD_MECHANISM_STATUS: what = "MECHANISM STATUS"; break;
|
||||
case GPCMD_READ_CD: what = "READ CD"; break;
|
||||
case 0xE1: what = "WRITE CONTINUE"; break;
|
||||
case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
|
||||
default: what = "(unknown command)"; break;
|
||||
}
|
||||
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(const struct us_data *us,
|
||||
unsigned char key,
|
||||
unsigned char asc,
|
||||
unsigned char ascq)
|
||||
{
|
||||
const char *what, *keystr;
|
||||
|
||||
keystr = scsi_sense_key_string(key);
|
||||
what = scsi_extd_sense_format(asc, ascq);
|
||||
|
||||
if (keystr == NULL)
|
||||
keystr = "(Unknown Key)";
|
||||
if (what == NULL)
|
||||
what = "(unknown ASC/ASCQ)";
|
||||
|
||||
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);
|
69
drivers/usb/storage/debug.h
Normal file
69
drivers/usb/storage/debug.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* Debugging Functions Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* Initial work by:
|
||||
* (c) 1999 Michael Gee (michael@linuxspecific.com)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define USB_STORAGE "usb-storage: "
|
||||
|
||||
#ifdef CONFIG_USB_STORAGE_DEBUG
|
||||
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
|
||||
__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
|
||||
|
||||
#endif
|
2420
drivers/usb/storage/ene_ub6250.c
Normal file
2420
drivers/usb/storage/ene_ub6250.c
Normal file
File diff suppressed because it is too large
Load diff
560
drivers/usb/storage/freecom.c
Normal file
560
drivers/usb/storage/freecom.c
Normal file
|
@ -0,0 +1,560 @@
|
|||
/* Driver for Freecom USB/IDE adaptor
|
||||
*
|
||||
* Freecom v0.1:
|
||||
*
|
||||
* First release
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (C) 2000 David Brown <usb-storage@davidb.org>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This driver was developed with information provided in FREECOM's USB
|
||||
* Programmers Reference Guide. For further information contact Freecom
|
||||
* (http://www.freecom.de/)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "transport.h"
|
||||
#include "protocol.h"
|
||||
#include "debug.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(struct us_data *us, void *ibuffer, int length);
|
||||
#endif
|
||||
|
||||
/* Bits of HD_STATUS */
|
||||
#define ERR_STAT 0x01
|
||||
#define DRQ_STAT 0x08
|
||||
|
||||
/* All of the outgoing packets are 64 bytes long. */
|
||||
struct freecom_cb_wrap {
|
||||
u8 Type; /* Command type. */
|
||||
u8 Timeout; /* Timeout in seconds. */
|
||||
u8 Atapi[12]; /* An ATAPI packet. */
|
||||
u8 Filler[50]; /* Padding Data. */
|
||||
};
|
||||
|
||||
struct freecom_xfer_wrap {
|
||||
u8 Type; /* Command type. */
|
||||
u8 Timeout; /* Timeout in seconds. */
|
||||
__le32 Count; /* Number of bytes to transfer. */
|
||||
u8 Pad[58];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct freecom_ide_out {
|
||||
u8 Type; /* Type + IDE register. */
|
||||
u8 Pad;
|
||||
__le16 Value; /* Value to write. */
|
||||
u8 Pad2[60];
|
||||
};
|
||||
|
||||
struct freecom_ide_in {
|
||||
u8 Type; /* Type | IDE register. */
|
||||
u8 Pad[63];
|
||||
};
|
||||
|
||||
struct freecom_status {
|
||||
u8 Status;
|
||||
u8 Reason;
|
||||
__le16 Count;
|
||||
u8 Pad[60];
|
||||
};
|
||||
|
||||
/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
|
||||
* register. */
|
||||
#define FCM_INT_STATUS 0x02 /* INDEX_STAT */
|
||||
#define FCM_STATUS_BUSY 0x80
|
||||
|
||||
/* These are the packet types. The low bit indicates that this command
|
||||
* should wait for an interrupt. */
|
||||
#define FCM_PACKET_ATAPI 0x21
|
||||
#define FCM_PACKET_STATUS 0x20
|
||||
|
||||
/* Receive data from the IDE interface. The ATAPI packet has already
|
||||
* waited, so the data should be immediately available. */
|
||||
#define FCM_PACKET_INPUT 0x81
|
||||
|
||||
/* Send data to the IDE interface. */
|
||||
#define FCM_PACKET_OUTPUT 0x01
|
||||
|
||||
/* Write a value to an ide register. Or the ide register to write after
|
||||
* munging the address a bit. */
|
||||
#define FCM_PACKET_IDE_WRITE 0x40
|
||||
#define FCM_PACKET_IDE_READ 0xC0
|
||||
|
||||
/* All packets (except for status) are 64 bytes long. */
|
||||
#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)
|
||||
{
|
||||
struct freecom_xfer_wrap *fxfr =
|
||||
(struct freecom_xfer_wrap *) us->iobuf;
|
||||
int result;
|
||||
|
||||
fxfr->Type = FCM_PACKET_INPUT | 0x00;
|
||||
fxfr->Timeout = 0; /* Short timeout for debugging. */
|
||||
fxfr->Count = cpu_to_le32 (count);
|
||||
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
|
||||
|
||||
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) {
|
||||
usb_stor_dbg(us, "Freecom readdata transport error\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* Now transfer all of our blocks. */
|
||||
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;
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
static int
|
||||
freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
|
||||
int unsigned ipipe, unsigned int opipe, int count)
|
||||
{
|
||||
struct freecom_xfer_wrap *fxfr =
|
||||
(struct freecom_xfer_wrap *) us->iobuf;
|
||||
int result;
|
||||
|
||||
fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
|
||||
fxfr->Timeout = 0; /* Short timeout for debugging. */
|
||||
fxfr->Count = cpu_to_le32 (count);
|
||||
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
|
||||
|
||||
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) {
|
||||
usb_stor_dbg(us, "Freecom writedata transport error\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* Now transfer all of our blocks. */
|
||||
usb_stor_dbg(us, "Start of write\n");
|
||||
result = usb_stor_bulk_srb(us, opipe, srb);
|
||||
|
||||
usb_stor_dbg(us, "freecom_writedata done!\n");
|
||||
if (result > USB_STOR_XFER_SHORT)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transport for the Freecom USB/IDE adaptor.
|
||||
*
|
||||
*/
|
||||
static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
|
||||
{
|
||||
struct freecom_cb_wrap *fcb;
|
||||
struct freecom_status *fst;
|
||||
unsigned int ipipe, opipe; /* We need both pipes. */
|
||||
int result;
|
||||
unsigned int partial;
|
||||
int length;
|
||||
|
||||
fcb = (struct freecom_cb_wrap *) us->iobuf;
|
||||
fst = (struct freecom_status *) us->iobuf;
|
||||
|
||||
usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
|
||||
|
||||
/* Get handles for both transports. */
|
||||
opipe = us->send_bulk_pipe;
|
||||
ipipe = us->recv_bulk_pipe;
|
||||
|
||||
/* The ATAPI Command always goes out first. */
|
||||
fcb->Type = FCM_PACKET_ATAPI | 0x00;
|
||||
fcb->Timeout = 0;
|
||||
memcpy (fcb->Atapi, srb->cmnd, 12);
|
||||
memset (fcb->Filler, 0, sizeof (fcb->Filler));
|
||||
|
||||
US_DEBUG(pdump(us, srb->cmnd, 12));
|
||||
|
||||
/* Send it out. */
|
||||
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
|
||||
FCM_PACKET_LENGTH, NULL);
|
||||
|
||||
/* The Freecom device will only fail if there is something wrong in
|
||||
* USB land. It returns the status in its own registers, which
|
||||
* come back in the bulk pipe. */
|
||||
if (result != USB_STOR_XFER_GOOD) {
|
||||
usb_stor_dbg(us, "freecom transport error\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* There are times we can optimize out this status read, but it
|
||||
* doesn't hurt us to always do it now. */
|
||||
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
|
||||
FCM_STATUS_PACKET_LENGTH, &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(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.
|
||||
*
|
||||
* 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) {
|
||||
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;
|
||||
fcb->Timeout = 0;
|
||||
memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
|
||||
memset (fcb->Filler, 0, sizeof (fcb->Filler));
|
||||
|
||||
/* Send it out. */
|
||||
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
|
||||
FCM_PACKET_LENGTH, NULL);
|
||||
|
||||
/* The Freecom device will only fail if there is something
|
||||
* wrong in USB land. It returns the status in its own
|
||||
* registers, which come back in the bulk pipe.
|
||||
*/
|
||||
if (result != USB_STOR_XFER_GOOD) {
|
||||
usb_stor_dbg(us, "freecom transport error\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
/* get the data */
|
||||
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
|
||||
FCM_STATUS_PACKET_LENGTH, &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(us, (void *)fst, partial));
|
||||
}
|
||||
|
||||
if (partial != 4)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
if ((fst->Status & 1) != 0) {
|
||||
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. */
|
||||
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 = scsi_bufflen(srb);
|
||||
}
|
||||
|
||||
/* verify that this amount is legal */
|
||||
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
|
||||
* move in. */
|
||||
|
||||
switch (us->srb->sc_data_direction) {
|
||||
case DMA_FROM_DEVICE:
|
||||
/* catch bogus "read 0 length" case */
|
||||
if (!length)
|
||||
break;
|
||||
/* Make sure that the status indicates that the device
|
||||
* wants data as well. */
|
||||
if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
|
||||
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;
|
||||
|
||||
usb_stor_dbg(us, "Waiting for status\n");
|
||||
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
|
||||
FCM_PACKET_LENGTH, &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) {
|
||||
usb_stor_dbg(us, "operation failed\n");
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
if ((fst->Reason & 3) != 3) {
|
||||
usb_stor_dbg(us, "Drive seems still hungry\n");
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
usb_stor_dbg(us, "Transfer happy\n");
|
||||
break;
|
||||
|
||||
case DMA_TO_DEVICE:
|
||||
/* catch bogus "write 0 length" case */
|
||||
if (!length)
|
||||
break;
|
||||
/* Make sure the status indicates that the device wants to
|
||||
* send us data. */
|
||||
/* !!IMPLEMENT!! */
|
||||
result = freecom_writedata (srb, us, ipipe, opipe, length);
|
||||
if (result != USB_STOR_TRANSPORT_GOOD)
|
||||
return result;
|
||||
|
||||
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) {
|
||||
usb_stor_dbg(us, "operation failed\n");
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
if ((fst->Reason & 3) != 3) {
|
||||
usb_stor_dbg(us, "Drive seems still hungry\n");
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
}
|
||||
|
||||
usb_stor_dbg(us, "Transfer happy\n");
|
||||
break;
|
||||
|
||||
|
||||
case DMA_NONE:
|
||||
/* Easy, do nothing. */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* should never hit here -- filtered in usb.c */
|
||||
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;
|
||||
}
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
static int init_freecom(struct us_data *us)
|
||||
{
|
||||
int result;
|
||||
char *buffer = us->iobuf;
|
||||
|
||||
/* The DMA-mapped I/O buffer is 64 bytes long, just right for
|
||||
* all our packets. No need to allocate any extra buffer space.
|
||||
*/
|
||||
|
||||
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
|
||||
0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
|
||||
buffer[32] = '\0';
|
||||
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
|
||||
* drivers to make sure that all the attached perhiperals are
|
||||
* properly reset.
|
||||
*/
|
||||
|
||||
/* send reset */
|
||||
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
|
||||
0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
|
||||
usb_stor_dbg(us, "result from activate reset is %d\n", result);
|
||||
|
||||
/* wait 250ms */
|
||||
mdelay(250);
|
||||
|
||||
/* clear reset */
|
||||
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
|
||||
0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
|
||||
usb_stor_dbg(us, "result from clear reset is %d\n", result);
|
||||
|
||||
/* wait 3 seconds */
|
||||
mdelay(3 * 1000);
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
static int usb_stor_freecom_reset(struct us_data *us)
|
||||
{
|
||||
printk (KERN_CRIT "freecom reset called\n");
|
||||
|
||||
/* We don't really have this feature. */
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_STORAGE_DEBUG
|
||||
static void pdump(struct us_data *us, void *ibuffer, int length)
|
||||
{
|
||||
static char line[80];
|
||||
int offset = 0;
|
||||
unsigned char *buffer = (unsigned char *) ibuffer;
|
||||
int i, j;
|
||||
int from, base;
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < length; i++) {
|
||||
if ((i & 15) == 0) {
|
||||
if (i > 0) {
|
||||
offset += sprintf (line+offset, " - ");
|
||||
for (j = i - 16; j < i; j++) {
|
||||
if (buffer[j] >= 32 && buffer[j] <= 126)
|
||||
line[offset++] = buffer[j];
|
||||
else
|
||||
line[offset++] = '.';
|
||||
}
|
||||
line[offset] = 0;
|
||||
usb_stor_dbg(us, "%s\n", line);
|
||||
offset = 0;
|
||||
}
|
||||
offset += sprintf (line+offset, "%08x:", i);
|
||||
} else if ((i & 7) == 0) {
|
||||
offset += sprintf (line+offset, " -");
|
||||
}
|
||||
offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
|
||||
}
|
||||
|
||||
/* Add the last "chunk" of data. */
|
||||
from = (length - 1) % 16;
|
||||
base = ((length - 1) / 16) * 16;
|
||||
|
||||
for (i = from + 1; i < 16; i++)
|
||||
offset += sprintf (line+offset, " ");
|
||||
if (from < 8)
|
||||
offset += sprintf (line+offset, " ");
|
||||
offset += sprintf (line+offset, " - ");
|
||||
|
||||
for (i = 0; i <= from; i++) {
|
||||
if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
|
||||
line[offset++] = buffer[base+i];
|
||||
else
|
||||
line[offset++] = '.';
|
||||
}
|
||||
line[offset] = 0;
|
||||
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);
|
106
drivers/usb/storage/initializers.c
Normal file
106
drivers/usb/storage/initializers.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* Special Initializers for certain USB Mass Storage devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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/errno.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "initializers.h"
|
||||
#include "debug.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode */
|
||||
int usb_stor_euscsi_init(struct us_data *us)
|
||||
{
|
||||
int result;
|
||||
|
||||
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);
|
||||
usb_stor_dbg(us, "-- result is %d\n", result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is required to activate all four slots on the UCR-61S2B
|
||||
* flash reader */
|
||||
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;
|
||||
unsigned int partial;
|
||||
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
|
||||
|
||||
usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n");
|
||||
|
||||
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
|
||||
bcb->Tag = 0;
|
||||
bcb->DataTransferLength = cpu_to_le32(0);
|
||||
bcb->Flags = bcb->Lun = 0;
|
||||
bcb->Length = sizeof(init_string) - 1;
|
||||
memset(bcb->CDB, 0, sizeof(bcb->CDB));
|
||||
memcpy(bcb->CDB, init_string, sizeof(init_string) - 1);
|
||||
|
||||
res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
|
||||
US_BULK_CB_WRAP_LEN, &partial);
|
||||
if (res)
|
||||
return -EIO;
|
||||
|
||||
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 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, 1 * HZ);
|
||||
usb_stor_dbg(us, "Huawei mode set result is %d\n", result);
|
||||
return 0;
|
||||
}
|
50
drivers/usb/storage/initializers.h
Normal file
50
drivers/usb/storage/initializers.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Header file for Special Initializers for certain USB Mass Storage devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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 "usb.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
|
||||
* mode */
|
||||
int usb_stor_euscsi_init(struct us_data *us);
|
||||
|
||||
/* 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);
|
1572
drivers/usb/storage/isd200.c
Normal file
1572
drivers/usb/storage/isd200.c
Normal file
File diff suppressed because it is too large
Load diff
684
drivers/usb/storage/jumpshot.c
Normal file
684
drivers/usb/storage/jumpshot.c
Normal file
|
@ -0,0 +1,684 @@
|
|||
/* Driver for Lexar "Jumpshot" Compact Flash reader
|
||||
*
|
||||
* jumpshot driver v0.1:
|
||||
*
|
||||
* First release
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
|
||||
*
|
||||
* Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
|
||||
* which I used as a template for this driver.
|
||||
*
|
||||
* Some bugfixes and scatter-gather code by Gregory P. Smith
|
||||
* (greg-usb@electricrain.com)
|
||||
*
|
||||
* Fix for media change by Joerg Schneider (js@joergschneider.com)
|
||||
*
|
||||
* Developed with the assistance of:
|
||||
*
|
||||
* (C) 2002 Alan Stern <stern@rowland.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This driver attempts to support the Lexar Jumpshot USB CompactFlash
|
||||
* reader. Like many other USB CompactFlash readers, the Jumpshot contains
|
||||
* a USB-to-ATA chip.
|
||||
*
|
||||
* This driver supports reading and writing. If you're truly paranoid,
|
||||
* however, you can force the driver into a write-protected state by setting
|
||||
* the WP enable bits in jumpshot_handle_mode_sense. See the comments
|
||||
* in that routine.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "transport.h"
|
||||
#include "protocol.h"
|
||||
#include "debug.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)
|
||||
{
|
||||
if (len == 0)
|
||||
return USB_STOR_XFER_GOOD;
|
||||
|
||||
usb_stor_dbg(us, "len = %d\n", len);
|
||||
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
|
||||
data, len, NULL);
|
||||
}
|
||||
|
||||
|
||||
static inline int jumpshot_bulk_write(struct us_data *us,
|
||||
unsigned char *data,
|
||||
unsigned int len)
|
||||
{
|
||||
if (len == 0)
|
||||
return USB_STOR_XFER_GOOD;
|
||||
|
||||
usb_stor_dbg(us, "len = %d\n", len);
|
||||
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
|
||||
data, len, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int jumpshot_get_status(struct us_data *us)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!us)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
// send the setup
|
||||
rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
|
||||
0, 0xA0, 0, 7, us->iobuf, 1);
|
||||
|
||||
if (rc != USB_STOR_XFER_GOOD)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
if (us->iobuf[0] != 0x50) {
|
||||
usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
static int jumpshot_read_data(struct us_data *us,
|
||||
struct jumpshot_info *info,
|
||||
u32 sector,
|
||||
u32 sectors)
|
||||
{
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *buffer;
|
||||
unsigned char thistime;
|
||||
unsigned int totallen, alloclen;
|
||||
int len, result;
|
||||
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
|
||||
// supports beyond 24-bit addressing. It's kind of hard to test
|
||||
// since it requires > 8GB CF card.
|
||||
|
||||
if (sector > 0x0FFFFFFF)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
totallen = sectors * info->ssize;
|
||||
|
||||
// Since we don't read more than 64 KB 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.
|
||||
|
||||
alloclen = min(totallen, 65536u);
|
||||
buffer = kmalloc(alloclen, GFP_NOIO);
|
||||
if (buffer == NULL)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
do {
|
||||
// loop, never allocate or transfer more than 64k at once
|
||||
// (min(128k, 255*info->ssize) is the real limit)
|
||||
len = min(totallen, alloclen);
|
||||
thistime = (len / info->ssize) & 0xff;
|
||||
|
||||
command[0] = 0;
|
||||
command[1] = thistime;
|
||||
command[2] = sector & 0xFF;
|
||||
command[3] = (sector >> 8) & 0xFF;
|
||||
command[4] = (sector >> 16) & 0xFF;
|
||||
|
||||
command[5] = 0xE0 | ((sector >> 24) & 0x0F);
|
||||
command[6] = 0x20;
|
||||
|
||||
// send the setup + command
|
||||
result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
|
||||
0, 0x20, 0, 1, command, 7);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// read the result
|
||||
result = jumpshot_bulk_read(us, buffer, len);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
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, &sg_offset, TO_XFER_BUF);
|
||||
|
||||
sector += thistime;
|
||||
totallen -= len;
|
||||
} while (totallen > 0);
|
||||
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
|
||||
leave:
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int jumpshot_write_data(struct us_data *us,
|
||||
struct jumpshot_info *info,
|
||||
u32 sector,
|
||||
u32 sectors)
|
||||
{
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *buffer;
|
||||
unsigned char thistime;
|
||||
unsigned int totallen, alloclen;
|
||||
int len, result, waitcount;
|
||||
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
|
||||
// supports beyond 24-bit addressing. It's kind of hard to test
|
||||
// since it requires > 8GB CF card.
|
||||
//
|
||||
if (sector > 0x0FFFFFFF)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
totallen = sectors * info->ssize;
|
||||
|
||||
// Since we don't write more than 64 KB 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.
|
||||
|
||||
alloclen = min(totallen, 65536u);
|
||||
buffer = kmalloc(alloclen, GFP_NOIO);
|
||||
if (buffer == NULL)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
do {
|
||||
// loop, never allocate or transfer more than 64k at once
|
||||
// (min(128k, 255*info->ssize) is the real limit)
|
||||
|
||||
len = min(totallen, alloclen);
|
||||
thistime = (len / info->ssize) & 0xff;
|
||||
|
||||
// Get the data from the transfer buffer
|
||||
usb_stor_access_xfer_buf(buffer, len, us->srb,
|
||||
&sg, &sg_offset, FROM_XFER_BUF);
|
||||
|
||||
command[0] = 0;
|
||||
command[1] = thistime;
|
||||
command[2] = sector & 0xFF;
|
||||
command[3] = (sector >> 8) & 0xFF;
|
||||
command[4] = (sector >> 16) & 0xFF;
|
||||
|
||||
command[5] = 0xE0 | ((sector >> 24) & 0x0F);
|
||||
command[6] = 0x30;
|
||||
|
||||
// send the setup + command
|
||||
result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
|
||||
0, 0x20, 0, 1, command, 7);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// send the data
|
||||
result = jumpshot_bulk_write(us, buffer, len);
|
||||
if (result != USB_STOR_XFER_GOOD)
|
||||
goto leave;
|
||||
|
||||
// read the result. apparently the bulk write can complete
|
||||
// before the jumpshot drive is finished writing. so we loop
|
||||
// here until we get a good return code
|
||||
waitcount = 0;
|
||||
do {
|
||||
result = jumpshot_get_status(us);
|
||||
if (result != USB_STOR_TRANSPORT_GOOD) {
|
||||
// I have not experimented to find the smallest value.
|
||||
//
|
||||
msleep(50);
|
||||
}
|
||||
} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
|
||||
|
||||
if (result != USB_STOR_TRANSPORT_GOOD)
|
||||
usb_stor_dbg(us, "Gah! Waitcount = 10. Bad write!?\n");
|
||||
|
||||
sector += thistime;
|
||||
totallen -= len;
|
||||
} while (totallen > 0);
|
||||
|
||||
kfree(buffer);
|
||||
return result;
|
||||
|
||||
leave:
|
||||
kfree(buffer);
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
static int jumpshot_id_device(struct us_data *us,
|
||||
struct jumpshot_info *info)
|
||||
{
|
||||
unsigned char *command = us->iobuf;
|
||||
unsigned char *reply;
|
||||
int rc;
|
||||
|
||||
if (!info)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
command[0] = 0xE0;
|
||||
command[1] = 0xEC;
|
||||
reply = kmalloc(512, GFP_NOIO);
|
||||
if (!reply)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
// send the setup
|
||||
rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
|
||||
0, 0x20, 0, 6, command, 2);
|
||||
|
||||
if (rc != USB_STOR_XFER_GOOD) {
|
||||
usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n");
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
// read the reply
|
||||
rc = jumpshot_bulk_read(us, reply, 512);
|
||||
if (rc != USB_STOR_XFER_GOOD) {
|
||||
rc = USB_STOR_TRANSPORT_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
info->sectors = ((u32)(reply[117]) << 24) |
|
||||
((u32)(reply[116]) << 16) |
|
||||
((u32)(reply[115]) << 8) |
|
||||
((u32)(reply[114]) );
|
||||
|
||||
rc = USB_STOR_TRANSPORT_GOOD;
|
||||
|
||||
leave:
|
||||
kfree(reply);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int jumpshot_handle_mode_sense(struct us_data *us,
|
||||
struct scsi_cmnd * srb,
|
||||
int sense_6)
|
||||
{
|
||||
static unsigned char rw_err_page[12] = {
|
||||
0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
|
||||
};
|
||||
static unsigned char cache_page[12] = {
|
||||
0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static unsigned char rbac_page[12] = {
|
||||
0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static unsigned char timer_page[8] = {
|
||||
0x1C, 0x6, 0, 0, 0, 0
|
||||
};
|
||||
unsigned char pc, page_code;
|
||||
unsigned int i = 0;
|
||||
struct jumpshot_info *info = (struct jumpshot_info *) (us->extra);
|
||||
unsigned char *ptr = us->iobuf;
|
||||
|
||||
pc = srb->cmnd[2] >> 6;
|
||||
page_code = srb->cmnd[2] & 0x3F;
|
||||
|
||||
switch (pc) {
|
||||
case 0x0:
|
||||
usb_stor_dbg(us, "Current values\n");
|
||||
break;
|
||||
case 0x1:
|
||||
usb_stor_dbg(us, "Changeable values\n");
|
||||
break;
|
||||
case 0x2:
|
||||
usb_stor_dbg(us, "Default values\n");
|
||||
break;
|
||||
case 0x3:
|
||||
usb_stor_dbg(us, "Saves values\n");
|
||||
break;
|
||||
}
|
||||
|
||||
memset(ptr, 0, 8);
|
||||
if (sense_6) {
|
||||
ptr[2] = 0x00; // WP enable: 0x80
|
||||
i = 4;
|
||||
} else {
|
||||
ptr[3] = 0x00; // WP enable: 0x80
|
||||
i = 8;
|
||||
}
|
||||
|
||||
switch (page_code) {
|
||||
case 0x0:
|
||||
// vendor-specific mode
|
||||
info->sense_key = 0x05;
|
||||
info->sense_asc = 0x24;
|
||||
info->sense_ascq = 0x00;
|
||||
return USB_STOR_TRANSPORT_FAILED;
|
||||
|
||||
case 0x1:
|
||||
memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
|
||||
i += sizeof(rw_err_page);
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
memcpy(ptr + i, cache_page, sizeof(cache_page));
|
||||
i += sizeof(cache_page);
|
||||
break;
|
||||
|
||||
case 0x1B:
|
||||
memcpy(ptr + i, rbac_page, sizeof(rbac_page));
|
||||
i += sizeof(rbac_page);
|
||||
break;
|
||||
|
||||
case 0x1C:
|
||||
memcpy(ptr + i, timer_page, sizeof(timer_page));
|
||||
i += sizeof(timer_page);
|
||||
break;
|
||||
|
||||
case 0x3F:
|
||||
memcpy(ptr + i, timer_page, sizeof(timer_page));
|
||||
i += sizeof(timer_page);
|
||||
memcpy(ptr + i, rbac_page, sizeof(rbac_page));
|
||||
i += sizeof(rbac_page);
|
||||
memcpy(ptr + i, cache_page, sizeof(cache_page));
|
||||
i += sizeof(cache_page);
|
||||
memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
|
||||
i += sizeof(rw_err_page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sense_6)
|
||||
ptr[0] = i - 1;
|
||||
else
|
||||
((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
|
||||
usb_stor_set_xfer_buf(ptr, i, srb);
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
|
||||
static void jumpshot_info_destructor(void *extra)
|
||||
{
|
||||
// this routine is a placeholder...
|
||||
// currently, we don't allocate any extra blocks so we're okay
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Transport for the Lexar 'Jumpshot'
|
||||
//
|
||||
static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
|
||||
{
|
||||
struct jumpshot_info *info;
|
||||
int rc;
|
||||
unsigned long block, blocks;
|
||||
unsigned char *ptr = us->iobuf;
|
||||
static unsigned char inquiry_response[8] = {
|
||||
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
if (!us->extra) {
|
||||
us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
|
||||
if (!us->extra)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
us->extra_destructor = jumpshot_info_destructor;
|
||||
}
|
||||
|
||||
info = (struct jumpshot_info *) (us->extra);
|
||||
|
||||
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] == READ_CAPACITY) {
|
||||
info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec
|
||||
|
||||
rc = jumpshot_get_status(us);
|
||||
if (rc != USB_STOR_TRANSPORT_GOOD)
|
||||
return rc;
|
||||
|
||||
rc = jumpshot_id_device(us, info);
|
||||
if (rc != USB_STOR_TRANSPORT_GOOD)
|
||||
return rc;
|
||||
|
||||
usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
|
||||
info->sectors, info->ssize);
|
||||
|
||||
// build the reply
|
||||
//
|
||||
((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
|
||||
((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
|
||||
usb_stor_set_xfer_buf(ptr, 8, srb);
|
||||
|
||||
return USB_STOR_TRANSPORT_GOOD;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == MODE_SELECT_10) {
|
||||
usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == READ_10) {
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
|
||||
|
||||
usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return jumpshot_read_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == READ_12) {
|
||||
// I don't think we'll ever see a READ_12 but support it anyway...
|
||||
//
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
|
||||
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
|
||||
|
||||
usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return jumpshot_read_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == WRITE_10) {
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
|
||||
|
||||
usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
|
||||
block, blocks);
|
||||
return jumpshot_write_data(us, info, block, blocks);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == WRITE_12) {
|
||||
// I don't think we'll ever see a WRITE_12 but support it anyway...
|
||||
//
|
||||
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
|
||||
((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5]));
|
||||
|
||||
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
|
||||
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
|
||||
|
||||
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) {
|
||||
usb_stor_dbg(us, "TEST_UNIT_READY\n");
|
||||
return jumpshot_get_status(us);
|
||||
}
|
||||
|
||||
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] == MODE_SENSE) {
|
||||
usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
|
||||
return jumpshot_handle_mode_sense(us, srb, 1);
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == MODE_SENSE_10) {
|
||||
usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
|
||||
return jumpshot_handle_mode_sense(us, srb, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (srb->cmnd[0] == START_STOP) {
|
||||
/* this is used by sd.c'check_scsidisk_media_change to detect
|
||||
media change */
|
||||
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);
|
||||
if (rc == USB_STOR_TRANSPORT_GOOD) {
|
||||
info->sense_key = NO_SENSE;
|
||||
srb->result = SUCCESS;
|
||||
} else {
|
||||
info->sense_key = UNIT_ATTENTION;
|
||||
srb->result = SAM_STAT_CHECK_CONDITION;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
236
drivers/usb/storage/karma.c
Normal file
236
drivers/usb/storage/karma.c
Normal file
|
@ -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);
|
317
drivers/usb/storage/onetouch.c
Normal file
317
drivers/usb/storage/onetouch.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Support for the Maxtor OneTouch USB hard drive's button
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
|
||||
*
|
||||
* Initial work by:
|
||||
* Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
|
||||
*
|
||||
* Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb/input.h>
|
||||
#include "usb.h"
|
||||
#include "debug.h"
|
||||
|
||||
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];
|
||||
char phys[64];
|
||||
struct input_dev *dev; /* input device interface */
|
||||
struct usb_device *udev; /* usb device */
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
#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 = urb->status;
|
||||
int retval;
|
||||
|
||||
switch (status) {
|
||||
case 0: /* success */
|
||||
break;
|
||||
case -ECONNRESET: /* unlink */
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
/* -EPIPE: should clear the halt */
|
||||
default: /* error */
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
|
||||
input_sync(dev);
|
||||
|
||||
resubmit:
|
||||
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 = input_get_drvdata(dev);
|
||||
|
||||
onetouch->is_open = 1;
|
||||
onetouch->irq->dev = onetouch->udev;
|
||||
if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
|
||||
dev_err(&dev->dev, "usb_submit_urb failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_onetouch_close(struct input_dev *dev)
|
||||
{
|
||||
struct usb_onetouch *onetouch = input_get_drvdata(dev);
|
||||
|
||||
usb_kill_urb(onetouch->irq);
|
||||
onetouch->is_open = 0;
|
||||
}
|
||||
|
||||
#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;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
struct usb_onetouch *onetouch;
|
||||
struct input_dev *input_dev;
|
||||
int pipe, maxp;
|
||||
int error = -ENOMEM;
|
||||
|
||||
interface = ss->pusb_intf->cur_altsetting;
|
||||
|
||||
if (interface->desc.bNumEndpoints != 3)
|
||||
return -ENODEV;
|
||||
|
||||
endpoint = &interface->endpoint[2].desc;
|
||||
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_alloc_coherent(udev, ONETOUCH_PKT_LEN,
|
||||
GFP_KERNEL, &onetouch->data_dma);
|
||||
if (!onetouch->data)
|
||||
goto fail1;
|
||||
|
||||
onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!onetouch->irq)
|
||||
goto fail2;
|
||||
|
||||
onetouch->udev = udev;
|
||||
onetouch->dev = input_dev;
|
||||
|
||||
if (udev->manufacturer)
|
||||
strlcpy(onetouch->name, udev->manufacturer,
|
||||
sizeof(onetouch->name));
|
||||
if (udev->product) {
|
||||
if (udev->manufacturer)
|
||||
strlcat(onetouch->name, " ", sizeof(onetouch->name));
|
||||
strlcat(onetouch->name, udev->product, sizeof(onetouch->name));
|
||||
}
|
||||
|
||||
if (!strlen(onetouch->name))
|
||||
snprintf(onetouch->name, sizeof(onetouch->name),
|
||||
"Maxtor Onetouch %04x:%04x",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
|
||||
usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys));
|
||||
strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys));
|
||||
|
||||
input_dev->name = onetouch->name;
|
||||
input_dev->phys = onetouch->phys;
|
||||
usb_to_input_id(udev, &input_dev->id);
|
||||
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_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,
|
||||
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
|
||||
|
||||
error = input_register_device(onetouch->dev);
|
||||
if (error)
|
||||
goto fail3;
|
||||
|
||||
return 0;
|
||||
|
||||
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 error;
|
||||
}
|
||||
|
||||
static void onetouch_release_input(void *onetouch_)
|
||||
{
|
||||
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
|
||||
|
||||
if (onetouch) {
|
||||
usb_kill_urb(onetouch->irq);
|
||||
input_unregister_device(onetouch->dev);
|
||||
usb_free_urb(onetouch->irq);
|
||||
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);
|
171
drivers/usb/storage/option_ms.c
Normal file
171
drivers/usb/storage/option_ms.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
4
drivers/usb/storage/option_ms.h
Normal file
4
drivers/usb/storage/option_ms.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef _OPTION_MS_H_
|
||||
#define _OPTION_MS_H_
|
||||
extern int option_ms_init(struct us_data *us);
|
||||
#endif
|
193
drivers/usb/storage/protocol.c
Normal file
193
drivers/usb/storage/protocol.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* Developed with the assistance of:
|
||||
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
|
||||
* (c) 2002 Alan Stern (stern@rowland.org)
|
||||
*
|
||||
* Initial work by:
|
||||
* (c) 1999 Michael Gee (michael@linuxspecific.com)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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/highmem.h>
|
||||
#include <linux/export.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "protocol.h"
|
||||
#include "debug.h"
|
||||
#include "scsiglue.h"
|
||||
#include "transport.h"
|
||||
|
||||
/***********************************************************************
|
||||
* Protocol routines
|
||||
***********************************************************************/
|
||||
|
||||
void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
|
||||
{
|
||||
/*
|
||||
* 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++)
|
||||
srb->cmnd[srb->cmd_len] = 0;
|
||||
|
||||
/* 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
|
||||
*
|
||||
* 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 (this affects the transport layer) */
|
||||
srb->cmd_len = 12;
|
||||
|
||||
/* XXX We should be constantly re-evaluating the need for these */
|
||||
|
||||
/* determine the correct data length for these commands */
|
||||
switch (srb->cmnd[0]) {
|
||||
|
||||
/* for INQUIRY, UFI devices only ever return 36 bytes */
|
||||
case INQUIRY:
|
||||
srb->cmnd[4] = 36;
|
||||
break;
|
||||
|
||||
/* again, for MODE_SENSE_10, we get the minimum (8) */
|
||||
case MODE_SENSE_10:
|
||||
srb->cmnd[7] = 0;
|
||||
srb->cmnd[8] = 8;
|
||||
break;
|
||||
|
||||
/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
|
||||
case REQUEST_SENSE:
|
||||
srb->cmnd[4] = 18;
|
||||
break;
|
||||
} /* end switch on cmnd[0] */
|
||||
|
||||
/* send the command to the transport layer */
|
||||
usb_stor_invoke_transport(srb, us);
|
||||
}
|
||||
|
||||
void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
|
||||
struct us_data *us)
|
||||
{
|
||||
/* 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.
|
||||
* 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, struct scatterlist **sgptr,
|
||||
unsigned int *offset, enum xfer_buf_dir dir)
|
||||
{
|
||||
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(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 cnt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf);
|
||||
|
||||
/* Store the contents of buffer into srb's transfer buffer and set the
|
||||
* SCSI residue.
|
||||
*/
|
||||
void usb_stor_set_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
struct scatterlist *sg = NULL;
|
||||
|
||||
buflen = min(buflen, scsi_bufflen(srb));
|
||||
buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
|
||||
TO_XFER_BUF);
|
||||
if (buflen < scsi_bufflen(srb))
|
||||
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_stor_set_xfer_buf);
|
57
drivers/usb/storage/protocol.h
Normal file
57
drivers/usb/storage/protocol.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* Protocol Functions Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PROTOCOL_H_
|
||||
#define _PROTOCOL_H_
|
||||
|
||||
/* Protocol handling routines */
|
||||
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*);
|
||||
|
||||
/* struct scsi_cmnd transfer buffer access utilities */
|
||||
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, struct scatterlist **,
|
||||
unsigned int *offset, enum xfer_buf_dir dir);
|
||||
|
||||
extern void usb_stor_set_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb);
|
||||
#endif
|
1073
drivers/usb/storage/realtek_cr.c
Normal file
1073
drivers/usb/storage/realtek_cr.c
Normal file
File diff suppressed because it is too large
Load diff
602
drivers/usb/storage/scsiglue.c
Normal file
602
drivers/usb/storage/scsiglue.c
Normal file
|
@ -0,0 +1,602 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* SCSI layer glue code
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* Developed with the assistance of:
|
||||
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
|
||||
* (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
|
||||
*
|
||||
* Initial work by:
|
||||
* (c) 1999 Michael Gee (michael@linuxspecific.com)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_devinfo.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "scsiglue.h"
|
||||
#include "debug.h"
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
struct us_data *us = host_to_us(sdev->host);
|
||||
|
||||
/* 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 (!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 != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB)
|
||||
sdev->use_10_for_ms = 1;
|
||||
|
||||
/* Many disks only accept MODE SENSE transfer lengths of
|
||||
* 192 bytes (that's what Windows uses). */
|
||||
sdev->use_192_bytes_for_3f = 1;
|
||||
|
||||
/* Some devices don't like MODE SENSE with page=0x3f,
|
||||
* which is the command used for checking if a device
|
||||
* is write-protected. Now that we tell the sd driver
|
||||
* to do a 192-byte transfer with this command the
|
||||
* 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->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->fflags & US_FL_FIX_CAPACITY)
|
||||
sdev->fix_capacity = 1;
|
||||
|
||||
/* 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,
|
||||
* recoverable or not. Setting this flag tells the SCSI
|
||||
* midlayer to retry such commands, which frequently will
|
||||
* succeed and fix the error. The worst this can lead to
|
||||
* 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 negligible 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->fflags & US_FL_NOT_LOCKABLE)
|
||||
sdev->lockable = 0;
|
||||
|
||||
/* this is to satisfy the compiler, tho I don't think the
|
||||
* return code is ever checked anywhere. */
|
||||
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_lck(struct scsi_cmnd *srb,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
struct us_data *us = host_to_us(srb->device->host);
|
||||
|
||||
/* check for state-transition errors */
|
||||
if (us->srb != NULL) {
|
||||
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
|
||||
__func__, us->srb);
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
}
|
||||
|
||||
/* fail the command if we are disconnecting */
|
||||
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;
|
||||
}
|
||||
|
||||
/* enqueue the command and wake up the control thread */
|
||||
srb->scsi_done = done;
|
||||
us->srb = srb;
|
||||
complete(&us->cmnd_ready);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEF_SCSI_QCMD(queuecommand)
|
||||
|
||||
/***********************************************************************
|
||||
* Error handling functions
|
||||
***********************************************************************/
|
||||
|
||||
/* Command timeout and abort */
|
||||
static int command_abort(struct scsi_cmnd *srb)
|
||||
{
|
||||
struct us_data *us = host_to_us(srb->device->host);
|
||||
|
||||
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. */
|
||||
scsi_lock(us_to_host(us));
|
||||
|
||||
/* Is this command still active? */
|
||||
if (us->srb != srb) {
|
||||
scsi_unlock(us_to_host(us));
|
||||
usb_stor_dbg(us, "-- nothing to abort\n");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
|
||||
* a device reset isn't already in progress (to avoid interfering
|
||||
* 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->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));
|
||||
|
||||
/* Wait for the aborted command to finish */
|
||||
wait_for_completion(&us->notify);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* This invokes the transport reset mechanism to reset the state of the
|
||||
* device */
|
||||
static int device_reset(struct scsi_cmnd *srb)
|
||||
{
|
||||
struct us_data *us = host_to_us(srb->device->host);
|
||||
int result;
|
||||
|
||||
usb_stor_dbg(us, "%s called\n", __func__);
|
||||
|
||||
/* lock the device pointers and do the reset */
|
||||
mutex_lock(&(us->dev_mutex));
|
||||
result = us->transport_reset(us);
|
||||
mutex_unlock(&us->dev_mutex);
|
||||
|
||||
return result < 0 ? FAILED : SUCCESS;
|
||||
}
|
||||
|
||||
/* Simulate a SCSI bus reset by resetting the device's USB port. */
|
||||
static int bus_reset(struct scsi_cmnd *srb)
|
||||
{
|
||||
struct us_data *us = host_to_us(srb->device->host);
|
||||
int result;
|
||||
|
||||
usb_stor_dbg(us, "%s called\n", __func__);
|
||||
|
||||
result = usb_stor_port_reset(us);
|
||||
return result < 0 ? FAILED : SUCCESS;
|
||||
}
|
||||
|
||||
/* Report a driver-initiated device reset to the SCSI layer.
|
||||
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
|
||||
* The caller must own the SCSI host lock. */
|
||||
void usb_stor_report_device_reset(struct us_data *us)
|
||||
{
|
||||
int i;
|
||||
struct Scsi_Host *host = us_to_host(us);
|
||||
|
||||
scsi_report_device_reset(host, 0, 0);
|
||||
if (us->fflags & US_FL_SCM_MULT_TARG) {
|
||||
for (i = 1; i < host->max_id; ++i)
|
||||
scsi_report_device_reset(host, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Report a driver-initiated bus reset to the SCSI layer.
|
||||
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
|
||||
* The caller must not own the SCSI host lock. */
|
||||
void usb_stor_report_bus_reset(struct us_data *us)
|
||||
{
|
||||
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...) seq_printf(m, ## args)
|
||||
|
||||
static int show_info (struct seq_file *m, struct Scsi_Host *host)
|
||||
{
|
||||
struct us_data *us = host_to_us(host);
|
||||
const char *string;
|
||||
|
||||
/* print the controller name */
|
||||
SPRINTF(" Host scsi%d: usb-storage\n", host->host_no);
|
||||
|
||||
/* print product, vendor, and serial number strings */
|
||||
if (us->pusb_dev->manufacturer)
|
||||
string = us->pusb_dev->manufacturer;
|
||||
else if (us->unusual_dev->vendorName)
|
||||
string = us->unusual_dev->vendorName;
|
||||
else
|
||||
string = "Unknown";
|
||||
SPRINTF(" Vendor: %s\n", string);
|
||||
if (us->pusb_dev->product)
|
||||
string = us->pusb_dev->product;
|
||||
else if (us->unusual_dev->productName)
|
||||
string = us->unusual_dev->productName;
|
||||
else
|
||||
string = "Unknown";
|
||||
SPRINTF(" Product: %s\n", string);
|
||||
if (us->pusb_dev->serial)
|
||||
string = us->pusb_dev->serial;
|
||||
else
|
||||
string = "None";
|
||||
SPRINTF("Serial Number: %s\n", string);
|
||||
|
||||
/* show the protocol and transport */
|
||||
SPRINTF(" Protocol: %s\n", us->protocol_name);
|
||||
SPRINTF(" Transport: %s\n", us->transport_name);
|
||||
|
||||
/* show the device flags */
|
||||
SPRINTF(" Quirks:");
|
||||
|
||||
#define US_FLAG(name, value) \
|
||||
if (us->fflags & value) seq_printf(m, " " #name);
|
||||
US_DO_ALL_FLAGS
|
||||
#undef US_FLAG
|
||||
seq_putc(m, '\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Sysfs interface
|
||||
***********************************************************************/
|
||||
|
||||
/* Output routine for the sysfs max_sectors file */
|
||||
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", queue_max_hw_sectors(sdev->request_queue));
|
||||
}
|
||||
|
||||
/* Input routine for the sysfs max_sectors file */
|
||||
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) {
|
||||
blk_queue_max_hw_sectors(sdev->request_queue, ms);
|
||||
return count;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
static DEVICE_ATTR_RW(max_sectors);
|
||||
|
||||
static struct device_attribute *sysfs_device_attr_list[] = {
|
||||
&dev_attr_max_sectors,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* this defines our host template, with which we'll allocate hosts
|
||||
*/
|
||||
|
||||
struct scsi_host_template usb_stor_host_template = {
|
||||
/* basic userland interface stuff */
|
||||
.name = "usb-storage",
|
||||
.proc_name = "usb-storage",
|
||||
.show_info = show_info,
|
||||
.write_info = write_info,
|
||||
.info = host_info,
|
||||
|
||||
/* command interface -- queued only */
|
||||
.queuecommand = queuecommand,
|
||||
|
||||
/* error and abort handlers */
|
||||
.eh_abort_handler = command_abort,
|
||||
.eh_device_reset_handler = device_reset,
|
||||
.eh_bus_reset_handler = bus_reset,
|
||||
|
||||
/* queue commands only, only one command per LUN */
|
||||
.can_queue = 1,
|
||||
.cmd_per_lun = 1,
|
||||
|
||||
/* unknown initiator id */
|
||||
.this_id = -1,
|
||||
|
||||
.slave_alloc = slave_alloc,
|
||||
.slave_configure = slave_configure,
|
||||
.target_alloc = target_alloc,
|
||||
|
||||
/* lots of sg segments can be handled */
|
||||
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
|
||||
|
||||
/* limit the total size of a transfer to 120 KB */
|
||||
.max_sectors = 240,
|
||||
|
||||
/* merge commands... this seems to help performance, but
|
||||
* periodically someone should test to see which setting is more
|
||||
* optimal.
|
||||
*/
|
||||
.use_clustering = 1,
|
||||
|
||||
/* emulated HBA */
|
||||
.emulated = 1,
|
||||
|
||||
/* we do our own delay after a device or bus reset */
|
||||
.skip_settle_delay = 1,
|
||||
|
||||
/* sysfs device attributes */
|
||||
.sdev_attrs = sysfs_device_attr_list,
|
||||
|
||||
/* module management */
|
||||
.module = THIS_MODULE
|
||||
};
|
||||
|
||||
/* To Report "Illegal Request: Invalid Field in CDB */
|
||||
unsigned char usb_stor_sense_invalidCDB[18] = {
|
||||
[0] = 0x70, /* current error */
|
||||
[2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */
|
||||
[7] = 0x0a, /* additional length */
|
||||
[12] = 0x24 /* Invalid Field in CDB */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(usb_stor_sense_invalidCDB);
|
48
drivers/usb/storage/scsiglue.h
Normal file
48
drivers/usb/storage/scsiglue.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* SCSI Connecting Glue Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SCSIGLUE_H_
|
||||
#define _SCSIGLUE_H_
|
||||
|
||||
extern void usb_stor_report_device_reset(struct us_data *us);
|
||||
extern void usb_stor_report_bus_reset(struct us_data *us);
|
||||
|
||||
extern unsigned char usb_stor_sense_invalidCDB[18];
|
||||
extern struct scsi_host_template usb_stor_host_template;
|
||||
|
||||
#endif
|
1782
drivers/usb/storage/sddr09.c
Normal file
1782
drivers/usb/storage/sddr09.c
Normal file
File diff suppressed because it is too large
Load diff
1006
drivers/usb/storage/sddr55.c
Normal file
1006
drivers/usb/storage/sddr55.c
Normal file
File diff suppressed because it is too large
Load diff
1874
drivers/usb/storage/shuttle_usbat.c
Normal file
1874
drivers/usb/storage/shuttle_usbat.c
Normal file
File diff suppressed because it is too large
Load diff
199
drivers/usb/storage/sierra_ms.c
Normal file
199
drivers/usb/storage/sierra_ms.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
4
drivers/usb/storage/sierra_ms.h
Normal file
4
drivers/usb/storage/sierra_ms.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef _SIERRA_MS_H_
|
||||
#define _SIERRA_MS_H_
|
||||
extern int sierra_ms_init(struct us_data *us);
|
||||
#endif
|
1407
drivers/usb/storage/transport.c
Normal file
1407
drivers/usb/storage/transport.c
Normal file
File diff suppressed because it is too large
Load diff
103
drivers/usb/storage/transport.h
Normal file
103
drivers/usb/storage/transport.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* Transport Functions Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TRANSPORT_H_
|
||||
#define _TRANSPORT_H_
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
|
||||
/*
|
||||
* usb_stor_bulk_transfer_xxx() return codes, in order of severity
|
||||
*/
|
||||
|
||||
#define USB_STOR_XFER_GOOD 0 /* good transfer */
|
||||
#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
|
||||
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
|
||||
#define USB_STOR_XFER_LONG 3 /* device tried to send too much */
|
||||
#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
|
||||
|
||||
/*
|
||||
* Transport return codes
|
||||
*/
|
||||
|
||||
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
|
||||
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
|
||||
#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
|
||||
#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
|
||||
|
||||
/*
|
||||
* We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
|
||||
* return codes. But now the transport and low-level transfer routines
|
||||
* treat an abort as just another error (-ENOENT for a cancelled URB).
|
||||
* It is up to the invoke_transport() function to test for aborts and
|
||||
* distinguish them from genuine communication errors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CBI accept device specific command
|
||||
*/
|
||||
|
||||
#define US_CBI_ADSC 0
|
||||
|
||||
extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
|
||||
extern int usb_stor_CB_reset(struct us_data*);
|
||||
|
||||
extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*);
|
||||
extern int usb_stor_Bulk_max_lun(struct us_data*);
|
||||
extern int usb_stor_Bulk_reset(struct us_data*);
|
||||
|
||||
extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*);
|
||||
extern void usb_stor_stop_transport(struct us_data*);
|
||||
|
||||
extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
|
||||
u8 request, u8 requesttype, u16 value, u16 index,
|
||||
void *data, u16 size, int timeout);
|
||||
extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
|
||||
|
||||
extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
|
||||
u8 request, u8 requesttype, u16 value, u16 index,
|
||||
void *data, u16 size);
|
||||
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
|
120
drivers/usb/storage/uas-detect.h
Normal file
120
drivers/usb/storage/uas-detect.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#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_find_uas_alt_setting(struct usb_interface *intf)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < intf->num_altsetting; i++) {
|
||||
struct usb_host_interface *alt = &intf->altsetting[i];
|
||||
|
||||
if (uas_is_interface(alt))
|
||||
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,
|
||||
unsigned long *flags_ret)
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* ASM1051 and older ASM1053 devices have the same usb-id, and UAS is
|
||||
* broken on the ASM1051, use the number of streams to differentiate.
|
||||
* New ASM1053-s also support 32 streams, but have a different prod-id.
|
||||
*/
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) == 0x174c &&
|
||||
le16_to_cpu(udev->descriptor.idProduct) == 0x55aa) {
|
||||
if (udev->speed < USB_SPEED_SUPER) {
|
||||
/* No streams info, assume ASM1051 */
|
||||
flags |= US_FL_IGNORE_UAS;
|
||||
} else if (usb_ss_max_streams(&eps[1]->ss_ep_comp) == 32) {
|
||||
flags |= US_FL_IGNORE_UAS;
|
||||
} else {
|
||||
/* ASM1053, these have issues with large transfers */
|
||||
flags |= US_FL_MAX_SECTORS_240;
|
||||
}
|
||||
}
|
||||
|
||||
usb_stor_adjust_quirks(udev, &flags);
|
||||
|
||||
if (flags & US_FL_IGNORE_UAS) {
|
||||
dev_warn(&udev->dev,
|
||||
"UAS is blacklisted for this device, using usb-storage instead\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (udev->bus->sg_tablesize == 0) {
|
||||
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 other USB controller if you wish to use UAS.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams) {
|
||||
dev_warn(&udev->dev,
|
||||
"USB controller %s does not support streams, which are required by the UAS driver.\n",
|
||||
hcd_to_bus(hcd)->bus_name);
|
||||
dev_warn(&udev->dev,
|
||||
"Please try an other USB controller if you wish to use UAS.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags_ret)
|
||||
*flags_ret = flags;
|
||||
|
||||
return 1;
|
||||
}
|
1173
drivers/usb/storage/uas.c
Normal file
1173
drivers/usb/storage/uas.c
Normal file
File diff suppressed because it is too large
Load diff
31
drivers/usb/storage/unusual_alauda.h
Normal file
31
drivers/usb/storage/unusual_alauda.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* 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
|
||||
* 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_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),
|
||||
|
||||
UNUSUAL_DEV( 0x07b4, 0x010a, 0x0102, 0x0102,
|
||||
"Olympus",
|
||||
"MAUSB-10 (Alauda)",
|
||||
USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0),
|
||||
|
||||
#endif /* defined(CONFIG_USB_STORAGE_ALAUDA) || ... */
|
39
drivers/usb/storage/unusual_cypress.h
Normal file
39
drivers/usb/storage/unusual_cypress.h
Normal file
|
@ -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) || ... */
|
98
drivers/usb/storage/unusual_datafab.h
Normal file
98
drivers/usb/storage/unusual_datafab.h
Normal file
|
@ -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) || ... */
|
2208
drivers/usb/storage/unusual_devs.h
Normal file
2208
drivers/usb/storage/unusual_devs.h
Normal file
File diff suppressed because it is too large
Load diff
26
drivers/usb/storage/unusual_ene_ub6250.h
Normal file
26
drivers/usb/storage/unusual_ene_ub6250.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*
|
||||
* 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_ENE_UB6250) || \
|
||||
defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE)
|
||||
|
||||
UNUSUAL_DEV(0x0cf2, 0x6250, 0x0000, 0x9999,
|
||||
"ENE",
|
||||
"ENE UB6250 reader",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
|
||||
|
||||
#endif /* defined(CONFIG_USB_STORAGE_ENE_UB6250) || ... */
|
26
drivers/usb/storage/unusual_freecom.h
Normal file
26
drivers/usb/storage/unusual_freecom.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* 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
|
||||
* 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_FREECOM) || \
|
||||
defined(CONFIG_USB_STORAGE_FREECOM_MODULE)
|
||||
|
||||
UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
|
||||
"Freecom",
|
||||
"USB-IDE",
|
||||
USB_SC_QIC, USB_PR_FREECOM, init_freecom, 0),
|
||||
|
||||
#endif /* defined(CONFIG_USB_STORAGE_FREECOM) || ... */
|
57
drivers/usb/storage/unusual_isd200.h
Normal file
57
drivers/usb/storage/unusual_isd200.h
Normal file
|
@ -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) || ... */
|
27
drivers/usb/storage/unusual_jumpshot.h
Normal file
27
drivers/usb/storage/unusual_jumpshot.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* 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
|
||||
* 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_JUMPSHOT) || \
|
||||
defined(CONFIG_USB_STORAGE_JUMPSHOT_MODULE)
|
||||
|
||||
UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
|
||||
"Lexar",
|
||||
"Jumpshot USB CF Reader",
|
||||
USB_SC_SCSI, USB_PR_JUMPSHOT, NULL,
|
||||
US_FL_NEED_OVERRIDE),
|
||||
|
||||
#endif /* defined(CONFIG_USB_STORAGE_JUMPSHOT) || ... */
|
26
drivers/usb/storage/unusual_karma.h
Normal file
26
drivers/usb/storage/unusual_karma.h
Normal file
|
@ -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) || ... */
|
36
drivers/usb/storage/unusual_onetouch.h
Normal file
36
drivers/usb/storage/unusual_onetouch.h
Normal file
|
@ -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) || ... */
|
41
drivers/usb/storage/unusual_realtek.h
Normal file
41
drivers/usb/storage/unusual_realtek.h
Normal file
|
@ -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) || ... */
|
56
drivers/usb/storage/unusual_sddr09.h
Normal file
56
drivers/usb/storage/unusual_sddr09.h
Normal file
|
@ -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) || ... */
|
44
drivers/usb/storage/unusual_sddr55.h
Normal file
44
drivers/usb/storage/unusual_sddr55.h
Normal file
|
@ -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) || ... */
|
161
drivers/usb/storage/unusual_uas.h
Normal file
161
drivers/usb/storage/unusual_uas.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/* 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>
|
||||
*/
|
||||
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=79511 */
|
||||
UNUSUAL_DEV(0x0bc2, 0x2312, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Expansion Desk",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* https://bbs.archlinux.org/viewtopic.php?id=183190 */
|
||||
UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Expansion Desk",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
|
||||
UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Expansion Desk",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Bogdan Mihalcea <bogdan.mihalcea@infim.ro> */
|
||||
UNUSUAL_DEV(0x0bc2, 0xa003, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Backup Plus",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Marcin Zajączkowski <mszpak@wp.pl> */
|
||||
UNUSUAL_DEV(0x0bc2, 0xa013, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Backup Plus",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
|
||||
UNUSUAL_DEV(0x0bc2, 0xa0a4, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Backup Plus Desk",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* https://bbs.archlinux.org/viewtopic.php?id=183190 */
|
||||
UNUSUAL_DEV(0x0bc2, 0xab20, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Backup+ BK",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* https://bbs.archlinux.org/viewtopic.php?id=183190 */
|
||||
UNUSUAL_DEV(0x0bc2, 0xab21, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"Backup+ BK",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: G. Richard Bellamy <rbellamy@pteradigm.com> */
|
||||
UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
|
||||
"Seagate",
|
||||
"BUP Fast HDD",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
|
||||
UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
|
||||
"Initio Corporation",
|
||||
"",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Tom Arild Naess <tanaess@gmail.com> */
|
||||
UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999,
|
||||
"JMicron",
|
||||
"JMS539",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_OPCODES),
|
||||
|
||||
/* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
|
||||
UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
|
||||
"JMicron",
|
||||
"JMS567",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_OPCODES),
|
||||
|
||||
/* Most ASM1051 based devices have issues with uas, blacklist them all */
|
||||
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
|
||||
UNUSUAL_DEV(0x174c, 0x5106, 0x0000, 0x9999,
|
||||
"ASMedia",
|
||||
"ASM1051",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_UAS),
|
||||
|
||||
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
|
||||
UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
|
||||
"VIA",
|
||||
"VL711",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_ATA_1X),
|
||||
|
||||
/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
|
||||
UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
|
||||
"JMicron",
|
||||
"JMS566",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_OPCODES),
|
||||
|
||||
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
|
||||
UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
|
||||
"Hitachi",
|
||||
"External HDD",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_UAS),
|
||||
|
||||
/* Reported-by: Richard Henderson <rth@redhat.com> */
|
||||
UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999,
|
||||
"SimpleTech",
|
||||
"External HDD",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_REPORT_OPCODES),
|
43
drivers/usb/storage/unusual_usbat.h
Normal file
43
drivers/usb/storage/unusual_usbat.h
Normal file
|
@ -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) || ... */
|
1133
drivers/usb/storage/usb.c
Normal file
1133
drivers/usb/storage/usb.c
Normal file
File diff suppressed because it is too large
Load diff
207
drivers/usb/storage/usb.h
Normal file
207
drivers/usb/storage/usb.h
Normal file
|
@ -0,0 +1,207 @@
|
|||
/* Driver for USB Mass Storage compliant devices
|
||||
* Main Header File
|
||||
*
|
||||
* Current development and maintenance by:
|
||||
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
||||
*
|
||||
* Initial work by:
|
||||
* (c) 1999 Michael Gee (michael@linuxspecific.com)
|
||||
*
|
||||
* This driver is based on the 'USB Mass Storage Class' document. This
|
||||
* describes in detail the protocol used to communicate with such
|
||||
* devices. Clearly, the designers had SCSI and ATAPI commands in
|
||||
* mind when they created this document. The commands are all very
|
||||
* similar to commands in the SCSI-II and ATAPI specifications.
|
||||
*
|
||||
* It is important to note that in a number of cases this class
|
||||
* exhibits class-specific exemptions from the USB specification.
|
||||
* Notably the usage of NAK, STALL and ACK differs from the norm, in
|
||||
* that they are used to communicate wait, failed and OK on commands.
|
||||
*
|
||||
* Also, for certain devices, the interrupt endpoint is used to convey
|
||||
* status of a command.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _USB_H_
|
||||
#define _USB_H_
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb_usual.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
struct us_data;
|
||||
struct scsi_cmnd;
|
||||
|
||||
/*
|
||||
* Unusual device list definitions
|
||||
*/
|
||||
|
||||
struct us_unusual_dev {
|
||||
const char* vendorName;
|
||||
const char* productName;
|
||||
__u8 useProtocol;
|
||||
__u8 useTransport;
|
||||
int (*initFunction)(struct us_data *);
|
||||
};
|
||||
|
||||
|
||||
/* 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
|
||||
|
||||
/*
|
||||
* We provide a DMA-mapped I/O buffer for use with small USB transfers.
|
||||
* It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
|
||||
* 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the
|
||||
* size we'll allocate.
|
||||
*/
|
||||
|
||||
#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */
|
||||
#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */
|
||||
|
||||
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 (*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_mutex to change 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 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;
|
||||
unsigned int recv_ctrl_pipe;
|
||||
unsigned int recv_intr_pipe;
|
||||
|
||||
/* information about the device */
|
||||
char *transport_name;
|
||||
char *protocol_name;
|
||||
__le32 bcs_signature;
|
||||
u8 subclass;
|
||||
u8 protocol;
|
||||
u8 max_lun;
|
||||
|
||||
u8 ifnum; /* interface number */
|
||||
u8 ep_bInterval; /* interrupt interval */
|
||||
|
||||
/* function pointers for this device */
|
||||
trans_cmnd transport; /* transport function */
|
||||
trans_reset transport_reset; /* transport device reset */
|
||||
proto_cmnd proto_handler; /* protocol handler */
|
||||
|
||||
/* 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 */
|
||||
dma_addr_t iobuf_dma; /* buffer DMA addresses */
|
||||
struct task_struct *ctl_thread; /* the control thread */
|
||||
|
||||
/* mutual exclusion and synchronization structures */
|
||||
struct completion cmnd_ready; /* to sleep thread on */
|
||||
struct completion notify; /* thread begin/end */
|
||||
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 inline struct Scsi_Host *us_to_host(struct us_data *us) {
|
||||
return container_of((void *) us, struct Scsi_Host, hostdata);
|
||||
}
|
||||
static inline struct us_data *host_to_us(struct Scsi_Host *host) {
|
||||
return (struct us_data *) host->hostdata;
|
||||
}
|
||||
|
||||
/* Function to fill an inquiry response. See usb.c for details */
|
||||
extern void fill_inquiry_response(struct us_data *us,
|
||||
unsigned char *data, unsigned int data_len);
|
||||
|
||||
/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
|
||||
* single queue element srb for write access */
|
||||
#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);
|
||||
|
||||
extern void usb_stor_adjust_quirks(struct usb_device *dev,
|
||||
unsigned long *fflags);
|
||||
|
||||
#endif
|
123
drivers/usb/storage/usual-tables.c
Normal file
123
drivers/usb/storage/usual-tables.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue