Creation of Cybook 2416 (actually Gen4) repository

This commit is contained in:
mlt
2009-12-18 17:10:00 +00:00
committed by godzil
commit 76f20f4d40
13791 changed files with 6812321 additions and 0 deletions

161
drivers/usb/storage/Kconfig Normal file
View File

@@ -0,0 +1,161 @@
#
# USB Storage driver configuration
#
comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'"
comment "may also be needed; see USB_STORAGE Help for more information"
depends on USB
config USB_STORAGE
tristate "USB Mass Storage support"
depends on USB && 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_DATAFAB
bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
help
Support for certain Datafab CompactFlash readers.
Datafab has a web page at <http://www.datafabusa.com/>.
config USB_STORAGE_FREECOM
bool "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/>.
config USB_STORAGE_ISD200
bool "ISD-200 USB/ATA Bridge support"
depends on USB_STORAGE
depends on BLK_DEV_IDE=y || BLK_DEV_IDE=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)
config USB_STORAGE_DPCM
bool "Microtech/ZiO! CompactFlash/SmartMedia support"
depends on USB_STORAGE
help
Say Y here to support the Microtech/ZiO! CompactFlash reader.
There is a web page at <http://www.ziocorp.com/products/>.
config USB_STORAGE_USBAT
bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
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
config USB_STORAGE_SDDR09
bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
help
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
Also works for the Microtech Zio! SmartMedia reader.
config USB_STORAGE_SDDR55
bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
help
Say Y here to include additional code to support the Sandisk SDDR-55
SmartMedia reader in the USB Mass Storage driver.
config USB_STORAGE_JUMPSHOT
bool "Lexar Jumpshot Compact Flash Reader (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
help
Say Y here to include additional code to support the Lexar Jumpshot
USB CompactFlash reader.
config USB_STORAGE_ALAUDA
bool "Olympus MAUSB-10/Fuji DPC-R1 support (EXPERIMENTAL)"
depends on USB_STORAGE && EXPERIMENTAL
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.
config USB_STORAGE_ONETOUCH
bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
depends on USB_STORAGE && INPUT_EVDEV && EXPERIMENTAL && !PM
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)
config USB_STORAGE_KARMA
bool "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.
config USB_LIBUSUAL
bool "The shared table of common (or usual) storage devices"
depends on USB
help
This module contains a table of common (or usual) devices
for usb-storage and ub drivers, and allows to switch binding
of these devices without rebuilding modules.
Typical syntax of /etc/modprobe.conf is:
options libusual bias="ub"
If unsure, say N.

View File

@@ -0,0 +1,30 @@
#
# Makefile for the USB Mass Storage device drivers.
#
# 15 Aug 2000, Christoph Hellwig <hch@infradead.org>
# Rewritten to use lists instead of if-statements.
#
EXTRA_CFLAGS := -Idrivers/scsi
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG) += debug.o
usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55) += sddr55.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
ifneq ($(CONFIG_USB_LIBUSUAL),)
obj-$(CONFIG_USB) += libusual.o
endif

1119
drivers/usb/storage/alauda.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
/*
* Driver for Alauda-based card readers
*
* Current development and maintenance by:
* (c) 2005 Daniel Drake <dsd@gentoo.org>
*
* See alauda.c for more explanation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_ALAUDA_H
#define _USB_ALAUDA_H
/*
* Status bytes
*/
#define ALAUDA_STATUS_ERROR 0x01
#define ALAUDA_STATUS_READY 0x40
/*
* Control opcodes (for request field)
*/
#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
#define ALAUDA_GET_SM_MEDIA_STATUS 0x98
#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
#define ALAUDA_ACK_SM_MEDIA_CHANGE 0x9a
#define ALAUDA_GET_XD_MEDIA_SIG 0x86
#define ALAUDA_GET_SM_MEDIA_SIG 0x96
/*
* Bulk command identity (byte 0)
*/
#define ALAUDA_BULK_CMD 0x40
/*
* Bulk opcodes (byte 1)
*/
#define ALAUDA_BULK_GET_REDU_DATA 0x85
#define ALAUDA_BULK_READ_BLOCK 0x94
#define ALAUDA_BULK_ERASE_BLOCK 0xa3
#define ALAUDA_BULK_WRITE_BLOCK 0xb4
#define ALAUDA_BULK_GET_STATUS2 0xb7
#define ALAUDA_BULK_RESET_MEDIA 0xe0
/*
* Port to operate on (byte 8)
*/
#define ALAUDA_PORT_XD 0x00
#define ALAUDA_PORT_SM 0x01
/*
* LBA and PBA are unsigned ints. Special values.
*/
#define UNDEF 0xffff
#define SPARE 0xfffe
#define UNUSABLE 0xfffd
int init_alauda(struct us_data *us);
int alauda_transport(struct scsi_cmnd *srb, struct us_data *us);
struct alauda_media_info {
unsigned long capacity; /* total media size in bytes */
unsigned int pagesize; /* page size in bytes */
unsigned int blocksize; /* number of pages per block */
unsigned int uzonesize; /* number of usable blocks per zone */
unsigned int zonesize; /* number of blocks per zone */
unsigned int blockmask; /* mask to get page from address */
unsigned char pageshift;
unsigned char blockshift;
unsigned char zoneshift;
u16 **lba_to_pba; /* logical to physical block map */
u16 **pba_to_lba; /* physical to logical block map */
};
struct alauda_info {
struct alauda_media_info port[2];
int wr_ep; /* endpoint to write data out of */
unsigned char sense_key;
unsigned long sense_asc; /* additional sense code */
unsigned long sense_ascq; /* additional sense code qualifier */
};
#endif

View File

@@ -0,0 +1,667 @@
/* Driver for Datafab USB Compact Flash reader
*
* $Id: datafab.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "datafab.h"
static int datafab_determine_lun(struct us_data *us,
struct datafab_info *info);
static inline int
datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
if (len == 0)
return USB_STOR_XFER_GOOD;
US_DEBUGP("datafab_bulk_read: len = %d\n", len);
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;
US_DEBUGP("datafab_bulk_write: 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_idx = 0, sg_offset = 0;
// 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_idx, &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_idx = 0, sg_offset = 0;
// 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_idx, &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) {
US_DEBUGP("datafab_write_data: 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 (!us || !info)
return USB_STOR_TRANSPORT_ERROR;
memcpy(command, scommand, 8);
buf = kmalloc(512, GFP_NOIO);
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("datafab_determine_lun: 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 (!us || !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:
US_DEBUGP("datafab_handle_mode_sense: Current values\n");
break;
case 0x1:
US_DEBUGP("datafab_handle_mode_sense: Changeable values\n");
break;
case 0x2:
US_DEBUGP("datafab_handle_mode_sense: Default values\n");
break;
case 0x3:
US_DEBUGP("datafab_handle_mode_sense: 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
//
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) {
US_DEBUGP("datafab_transport: Gah! "
"Can't allocate storage for Datafab info struct!\n");
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) {
US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response");
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;
US_DEBUGP("datafab_transport: 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) {
US_DEBUGP("datafab_transport: 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]));
US_DEBUGP("datafab_transport: 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]));
US_DEBUGP("datafab_transport: 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]));
US_DEBUGP("datafab_transport: 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]));
US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
return datafab_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n");
return datafab_id_device(us, info);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
US_DEBUGP("datafab_transport: 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) {
US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n");
return datafab_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n");
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 */
US_DEBUGP("datafab_transport: 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;
}
US_DEBUGP("datafab_transport: 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;
}

View File

@@ -0,0 +1,40 @@
/* Driver for Datafab MDCFE-B USB Compact Flash reader
* Header File
*
* Current development and maintenance by:
* (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
*
* See datafab.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_DATAFAB_MDCFE_B_H
#define _USB_DATAFAB_MDCFE_B_H
extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us);
struct datafab_info {
unsigned long sectors; // total sector count
unsigned long ssize; // sector size in bytes
signed char lun; // used for dual-slot readers
// the following aren't used yet
unsigned char sense_key;
unsigned long sense_asc; // additional sense code
unsigned long sense_ascq; // additional sense code qualifier
};
#endif

179
drivers/usb/storage/debug.c Normal file
View File

@@ -0,0 +1,179 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Source Code File
*
* $Id: debug.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/cdrom.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include "debug.h"
#include "scsi.h"
void usb_stor_show_command(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;
}
US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
US_DEBUGP("");
for (i = 0; i < srb->cmd_len && i < 16; i++)
US_DEBUGPX(" %02x", srb->cmnd[i]);
US_DEBUGPX("\n");
}
void usb_stor_show_sense(
unsigned char key,
unsigned char asc,
unsigned char ascq) {
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)";
US_DEBUGP("%s: ", keystr);
US_DEBUGPX(what, ascq);
US_DEBUGPX("\n");
}

View File

@@ -0,0 +1,64 @@
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Header File
*
* $Id: debug.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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(struct scsi_cmnd *srb);
void usb_stor_show_sense( unsigned char key,
unsigned char asc, unsigned char ascq );
#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
#define US_DEBUGPX(x...) printk( x )
#define US_DEBUG(x) x
#else
#define US_DEBUGP(x...)
#define US_DEBUGPX(x...)
#define US_DEBUG(x)
#endif
#endif

View File

@@ -0,0 +1,88 @@
/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
*
* $Id: dpcm.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* DPCM driver v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2000 Brian Webb (webbb@earthlink.net)
*
* This device contains both a CompactFlash card reader, which
* uses the Control/Bulk w/o Interrupt protocol and
* a SmartMedia card reader that uses the same protocol
* as the SDDR09.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "dpcm.h"
#include "sddr09.h"
/*
* Transport for the Microtech DPCM-USB
*
*/
int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int ret;
if(srb == NULL)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
switch(srb->device->lun) {
case 0:
/*
* LUN 0 corresponds to the CompactFlash card reader.
*/
ret = usb_stor_CB_transport(srb, us);
break;
#ifdef CONFIG_USB_STORAGE_SDDR09
case 1:
/*
* LUN 1 corresponds to the SmartMedia card reader.
*/
/*
* Set the LUN to 0 (just in case).
*/
srb->device->lun = 0; us->srb->device->lun = 0;
ret = sddr09_transport(srb, us);
srb->device->lun = 1; us->srb->device->lun = 1;
break;
#endif
default:
US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
ret = USB_STOR_TRANSPORT_ERROR;
break;
}
return ret;
}

View File

@@ -0,0 +1,34 @@
/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
*
* $Id: dpcm.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* DPCM driver v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2000 Brian Webb (webbb@earthlink.net)
*
* See dpcm.c for more explanation
*
* 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 _MICROTECH_DPCM_USB_H
#define _MICROTECH_DPCM_USB_H
extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us);
#endif

View File

@@ -0,0 +1,487 @@
/* Driver for Freecom USB/IDE adaptor
*
* $Id: freecom.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/hdreg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "freecom.h"
#ifdef CONFIG_USB_STORAGE_DEBUG
static void pdump (void *, int);
#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
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));
US_DEBUGP("Read data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom readdata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
US_DEBUGP("Start of read\n");
result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
count, srb->use_sg, &srb->resid);
US_DEBUGP("freecom_readdata done!\n");
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));
US_DEBUGP("Write data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP ("Freecom writedata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
US_DEBUGP("Start of write\n");
result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
count, srb->use_sg, &srb->resid);
US_DEBUGP("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.
*
*/
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;
US_DEBUGP("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 (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) {
US_DEBUGP ("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);
US_DEBUGP("foo Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUG(pdump ((void *) fst, partial));
/* 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) {
US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n");
US_DEBUGP("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) {
US_DEBUGP ("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);
US_DEBUGP("bar Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUG(pdump ((void *) fst, partial));
}
if (partial != 4)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & 1) != 0) {
US_DEBUGP("operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
/* The device might not have as much data available as we
* requested. If you ask for more than the device has, this reads
* and such will hang. */
US_DEBUGP("Device indicates that it has %d bytes available\n",
le16_to_cpu (fst->Count));
US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
/* Find the length we desire to read. */
switch (srb->cmnd[0]) {
case INQUIRY:
case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
case MODE_SENSE:
case MODE_SENSE_10:
length = le16_to_cpu(fst->Count);
break;
default:
length = srb->request_bufflen;
}
/* verify that this amount is legal */
if (length > srb->request_bufflen) {
length = srb->request_bufflen;
US_DEBUGP("Truncating request to match buffer length: %d\n", length);
}
/* 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) {
US_DEBUGP("SCSI wants data, drive doesn't have any\n");
return USB_STOR_TRANSPORT_FAILED;
}
result = freecom_readdata (srb, us, ipipe, opipe, length);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
US_DEBUGP("FCM: Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
US_DEBUG(pdump ((void *) fst, partial));
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
US_DEBUGP("operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
US_DEBUGP("Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
US_DEBUGP("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;
US_DEBUGP("FCM: Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
US_DEBUGP("operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
US_DEBUGP("Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
US_DEBUGP("Transfer happy\n");
break;
case DMA_NONE:
/* Easy, do nothing. */
break;
default:
/* should never hit here -- filtered in usb.c */
US_DEBUGP ("freecom unimplemented direction: %d\n",
us->srb->sc_data_direction);
// Return fail, SCSI seems to handle this better.
return USB_STOR_TRANSPORT_FAILED;
break;
}
return USB_STOR_TRANSPORT_GOOD;
}
int
freecom_init (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';
US_DEBUGP("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);
US_DEBUGP("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);
US_DEBUGP("result from clear reset is %d\n", result);
/* wait 3 seconds */
mdelay(3 * 1000);
return USB_STOR_TRANSPORT_GOOD;
}
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 (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;
US_DEBUGP("%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;
US_DEBUGP("%s\n", line);
offset = 0;
}
#endif

View File

@@ -0,0 +1,36 @@
/* Driver for Freecom USB/IDE adaptor
*
* $Id: freecom.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* Freecom v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2000 David Brown <usb-storage@davidb.org>
*
* See freecom.c for more explanation
*
* 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 _FREECOM_USB_H
#define _FREECOM_USB_H
extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us);
extern int usb_stor_freecom_reset(struct us_data *us);
extern int freecom_init (struct us_data *us);
#endif

View File

@@ -0,0 +1,92 @@
/* Special Initializers for certain USB Mass Storage devices
*
* $Id: initializers.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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;
US_DEBUGP("Attempting to init eUSCSI bridge...\n");
us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
0x01, 0x0, us->iobuf, 0x1, 5*HZ);
US_DEBUGP("-- result is %d\n", result);
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, partial;
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
US_DEBUGP("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 res;
US_DEBUGP("Getting status packet...\n");
res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &partial);
return (res ? -1 : 0);
}

View File

@@ -0,0 +1,49 @@
/* Header file for Special Initializers for certain USB Mass Storage devices
*
* $Id: initializers.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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);

1440
drivers/usb/storage/isd200.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
/* Header File for In-System Design, Inc. ISD200 ASIC
*
* First release
*
* Current development and maintenance by:
* (c) 2000 In-System Design, Inc. (support@in-system.com)
*
* See isd200.c for more information.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 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_ISD200_H
#define _USB_ISD200_H
extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us);
extern int isd200_Initialization(struct us_data *us);
#endif

View File

@@ -0,0 +1,594 @@
/* Driver for Lexar "Jumpshot" Compact Flash reader
*
* $Id: jumpshot.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "jumpshot.h"
static inline int jumpshot_bulk_read(struct us_data *us,
unsigned char *data,
unsigned int len)
{
if (len == 0)
return USB_STOR_XFER_GOOD;
US_DEBUGP("jumpshot_bulk_read: 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;
US_DEBUGP("jumpshot_bulk_write: 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) {
US_DEBUGP("jumpshot_get_status: 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_idx = 0, sg_offset = 0;
// 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;
US_DEBUGP("jumpshot_read_data: %d bytes\n", len);
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
&sg_idx, &sg_offset, TO_XFER_BUF);
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_idx = 0, sg_offset = 0;
// 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_idx, &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)
US_DEBUGP("jumpshot_write_data: 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 (!us || !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) {
US_DEBUGP("jumpshot_id_device: 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:
US_DEBUGP("jumpshot_handle_mode_sense: Current values\n");
break;
case 0x1:
US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n");
break;
case 0x2:
US_DEBUGP("jumpshot_handle_mode_sense: Default values\n");
break;
case 0x3:
US_DEBUGP("jumpshot_handle_mode_sense: 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'
//
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) {
US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n");
return USB_STOR_TRANSPORT_ERROR;
}
us->extra_destructor = jumpshot_info_destructor;
}
info = (struct jumpshot_info *) (us->extra);
if (srb->cmnd[0] == INQUIRY) {
US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n");
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;
US_DEBUGP("jumpshot_transport: 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) {
US_DEBUGP("jumpshot_transport: 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]));
US_DEBUGP("jumpshot_transport: 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]));
US_DEBUGP("jumpshot_transport: 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]));
US_DEBUGP("jumpshot_transport: 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]));
US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
return jumpshot_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n");
return jumpshot_get_status(us);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
US_DEBUGP("jumpshot_transport: 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) {
US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n");
return jumpshot_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n");
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 */
US_DEBUGP("jumpshot_transport: 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;
}
US_DEBUGP("jumpshot_transport: 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;
}

View File

@@ -0,0 +1,39 @@
/* Driver for Lexar "Jumpshot" USB Compact Flash reader
* Header File
*
* Current development and maintenance by:
* (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
*
* See jumpshot.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_JUMPSHOT_H
#define _USB_JUMPSHOT_H
extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us);
struct jumpshot_info {
unsigned long sectors; // total sector count
unsigned long ssize; // sector size in bytes
// the following aren't used yet
unsigned char sense_key;
unsigned long sense_asc; // additional sense code
unsigned long sense_ascq; // additional sense code qualifier
};
#endif

155
drivers/usb/storage/karma.c Normal file
View File

@@ -0,0 +1,155 @@
/* 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 <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "transport.h"
#include "debug.h"
#include "karma.h"
#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
extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data *);
struct karma_data {
int in_storage;
char *recv;
};
/*
* 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;
US_DEBUGP("karma: 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;
US_DEBUGP("karma: sent command %04x\n", cmd);
return 0;
err:
US_DEBUGP("karma: 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.
*/
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);
}
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;
}

View File

@@ -0,0 +1,7 @@
#ifndef _KARMA_USB_H
#define _KARMA_USB_H
extern int rio_karma_init(struct us_data *us);
extern int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us);
#endif

View File

@@ -0,0 +1,266 @@
/*
* libusual
*
* The libusual contains the table of devices common for ub and usb-storage.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/vmalloc.h>
#include <linux/kthread.h>
/*
*/
#define USU_MOD_FL_THREAD 1 /* Thread is running */
#define USU_MOD_FL_PRESENT 2 /* The module is loaded */
struct mod_status {
unsigned long fls;
};
static struct mod_status stat[3];
static DEFINE_SPINLOCK(usu_lock);
/*
*/
#define USB_US_DEFAULT_BIAS USB_US_TYPE_STOR
static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
#define BIAS_NAME_SIZE (sizeof("usb-storage"))
static const char *bias_names[3] = { "none", "usb-storage", "ub" };
static DECLARE_MUTEX_LOCKED(usu_init_notify);
static DECLARE_COMPLETION(usu_end_notify);
static atomic_t total_threads = ATOMIC_INIT(0);
static int usu_probe_thread(void *arg);
/*
* The table.
*/
#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)|(USB_US_TYPE_STOR<<24) }
#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
.driver_info = ((useType)<<24) }
struct usb_device_id storage_usb_ids [] = {
# include "unusual_devs.h"
{ } /* Terminating entry */
};
#undef USUAL_DEV
#undef UNUSUAL_DEV
MODULE_DEVICE_TABLE(usb, storage_usb_ids);
EXPORT_SYMBOL_GPL(storage_usb_ids);
/*
* @type: the module type as an integer
*/
void usb_usual_set_present(int type)
{
struct mod_status *st;
unsigned long flags;
if (type <= 0 || type >= 3)
return;
st = &stat[type];
spin_lock_irqsave(&usu_lock, flags);
st->fls |= USU_MOD_FL_PRESENT;
spin_unlock_irqrestore(&usu_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_usual_set_present);
void usb_usual_clear_present(int type)
{
struct mod_status *st;
unsigned long flags;
if (type <= 0 || type >= 3)
return;
st = &stat[type];
spin_lock_irqsave(&usu_lock, flags);
st->fls &= ~USU_MOD_FL_PRESENT;
spin_unlock_irqrestore(&usu_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_usual_clear_present);
/*
* Match the calling driver type against the table.
* Returns: 0 if the device matches.
*/
int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
{
int id_type = USB_US_TYPE(id->driver_info);
if (caller_type <= 0 || caller_type >= 3)
return -EINVAL;
/* Drivers grab fixed assignment devices */
if (id_type == caller_type)
return 0;
/* Drivers grab devices biased to them */
if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias))
return 0;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(usb_usual_check_type);
/*
*/
static int usu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
unsigned long type;
struct task_struct* task;
unsigned long flags;
type = USB_US_TYPE(id->driver_info);
if (type == 0)
type = atomic_read(&usu_bias);
spin_lock_irqsave(&usu_lock, flags);
if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) {
spin_unlock_irqrestore(&usu_lock, flags);
return -ENXIO;
}
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
if (IS_ERR(task)) {
int rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
"Unable to start the thread for %s: %d\n",
bias_names[type], rc);
spin_lock_irqsave(&usu_lock, flags);
stat[type].fls &= ~USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
return rc; /* Not being -ENXIO causes a message printed */
}
atomic_inc(&total_threads);
return -ENXIO;
}
static void usu_disconnect(struct usb_interface *intf)
{
; /* We should not be here. */
}
static struct usb_driver usu_driver = {
.name = "libusual",
.probe = usu_probe,
.disconnect = usu_disconnect,
.id_table = storage_usb_ids,
};
/*
* A whole new thread for a purpose of request_module seems quite stupid.
* The request_module forks once inside again. However, if we attempt
* to load a storage module from our own modprobe thread, that module
* references our symbols, which cannot be resolved until our module is
* initialized. I wish there was a way to wait for the end of initialization.
* The module notifier reports MODULE_STATE_COMING only.
* So, we wait until module->init ends as the next best thing.
*/
static int usu_probe_thread(void *arg)
{
int type = (unsigned long) arg;
struct mod_status *st = &stat[type];
int rc;
unsigned long flags;
/* A completion does not work here because it's counted. */
down(&usu_init_notify);
up(&usu_init_notify);
rc = request_module(bias_names[type]);
spin_lock_irqsave(&usu_lock, flags);
if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
/*
* This should not happen, but let us keep tabs on it.
*/
printk(KERN_NOTICE "libusual: "
"modprobe for %s succeeded, but module is not present\n",
bias_names[type]);
}
st->fls &= ~USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
complete_and_exit(&usu_end_notify, 0);
}
/*
*/
static int __init usb_usual_init(void)
{
int rc;
rc = usb_register(&usu_driver);
up(&usu_init_notify);
return rc;
}
static void __exit usb_usual_exit(void)
{
/*
* We do not check for any drivers present, because
* they keep us pinned with symbol references.
*/
usb_deregister(&usu_driver);
while (atomic_read(&total_threads) > 0) {
wait_for_completion(&usu_end_notify);
atomic_dec(&total_threads);
}
}
/*
* Validate and accept the bias parameter.
*/
static int usu_set_bias(const char *bias_s, struct kernel_param *kp)
{
int i;
int len;
int bias_n = 0;
len = strlen(bias_s);
if (len == 0)
return -EDOM;
if (bias_s[len-1] == '\n')
--len;
for (i = 1; i < 3; i++) {
if (strncmp(bias_s, bias_names[i], len) == 0) {
bias_n = i;
break;
}
}
if (bias_n == 0)
return -EINVAL;
atomic_set(&usu_bias, bias_n);
return 0;
}
static int usu_get_bias(char *buffer, struct kernel_param *kp)
{
return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)]));
}
module_init(usb_usual_init);
module_exit(usb_usual_exit);
module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR);
__MODULE_PARM_TYPE(bias, "string");
MODULE_PARM_DESC(bias, "Bias to usb-storage or ub");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,235 @@
/*
* 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/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include "usb.h"
#include "onetouch.h"
#include "debug.h"
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;
};
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;
switch (urb->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:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
onetouch->udev->bus->bus_name,
onetouch->udev->devpath, status);
}
static int usb_onetouch_open(struct input_dev *dev)
{
struct usb_onetouch *onetouch = dev->private;
onetouch->is_open = 1;
onetouch->irq->dev = onetouch->udev;
if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
err("usb_submit_urb failed");
return -EIO;
}
return 0;
}
static void usb_onetouch_close(struct input_dev *dev)
{
struct usb_onetouch *onetouch = dev->private;
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_KERNEL) != 0)
err("usb_submit_urb failed");
break;
default:
break;
}
}
}
#endif /* CONFIG_PM */
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));
onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!onetouch || !input_dev)
goto fail1;
onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
GFP_ATOMIC, &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->cdev.dev = &udev->dev;
set_bit(EV_KEY, input_dev->evbit);
set_bit(ONETOUCH_BUTTON, input_dev->keybit);
clear_bit(0, input_dev->keybit);
input_dev->private = onetouch;
input_dev->open = usb_onetouch_open;
input_dev->close = usb_onetouch_close;
usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
(maxp > 8 ? 8 : maxp),
usb_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_buffer_free(udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
fail1: kfree(onetouch);
input_free_device(input_dev);
return error;
}
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_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
}
}

View File

@@ -0,0 +1,9 @@
#ifndef _ONETOUCH_H_
#define _ONETOUCH_H_
#define ONETOUCH_PKT_LEN 0x02
#define ONETOUCH_BUTTON KEY_PROG1
int onetouch_connect_input(struct us_data *ss);
#endif

View File

@@ -0,0 +1,254 @@
/* Driver for USB Mass Storage compliant devices
*
* $Id: protocol.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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 <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_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* Pad the ATAPI command with zeros
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
/* set command length to 12 bytes */
srb->cmd_len = 12;
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* Pad the ATAPI command with zeros
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
*/
/* Pad the ATAPI command with zeros */
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
/* set command length to 12 bytes */
srb->cmd_len = 12;
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* fix some commands -- this is a form of mode translation
* UFI devices only accept 12 byte long commands
*
* 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);
}
/***********************************************************************
* Scatter-gather transfer buffer access routines
***********************************************************************/
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
* (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
* points to a list of s-g entries and we ignore srb->request_bufflen.
* For non-scatter-gather transfers, srb->request_buffer points to the
* transfer buffer itself and srb->request_bufflen is the buffer's length.)
* Update the *index and *offset variables so that the next copy will
* pick up from where this one left off. */
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
unsigned int *offset, enum xfer_buf_dir dir)
{
unsigned int cnt;
/* If not using scatter-gather, just transfer the data directly.
* Make certain it will fit in the available buffer space. */
if (srb->use_sg == 0) {
if (*offset >= srb->request_bufflen)
return 0;
cnt = min(buflen, srb->request_bufflen - *offset);
if (dir == TO_XFER_BUF)
memcpy((unsigned char *) srb->request_buffer + *offset,
buffer, cnt);
else
memcpy(buffer, (unsigned char *) srb->request_buffer +
*offset, cnt);
*offset += cnt;
/* Using scatter-gather. We have to go through the list one entry
* at a time. Each s-g entry contains some number of pages, and
* each page has to be kmap()'ed separately. If the page is already
* in kernel-addressable memory then kmap() will return its address.
* If the page is not directly accessible -- such as a user buffer
* located in high memory -- then kmap() will map it to a temporary
* position in the kernel's virtual address space. */
} else {
struct scatterlist *sg =
(struct scatterlist *) srb->request_buffer
+ *index;
/* This loop handles a single s-g list entry, which may
* include multiple pages. Find the initial page structure
* and the starting offset within the page, and update
* the *offset and *index values for the next loop. */
cnt = 0;
while (cnt < buflen && *index < srb->use_sg) {
struct page *page = sg->page +
((sg->offset + *offset) >> PAGE_SHIFT);
unsigned int poff =
(sg->offset + *offset) & (PAGE_SIZE-1);
unsigned int sglen = sg->length - *offset;
if (sglen > buflen - cnt) {
/* Transfer ends within this s-g entry */
sglen = buflen - cnt;
*offset += sglen;
} else {
/* Transfer continues to next s-g entry */
*offset = 0;
++*index;
++sg;
}
/* Transfer the data for all the pages in this
* s-g entry. For each page: call kmap(), do the
* transfer, and call kunmap() immediately after. */
while (sglen > 0) {
unsigned int plen = min(sglen, (unsigned int)
PAGE_SIZE - poff);
unsigned char *ptr = kmap(page);
if (dir == TO_XFER_BUF)
memcpy(ptr + poff, buffer + cnt, plen);
else
memcpy(buffer + cnt, ptr + poff, plen);
kunmap(page);
/* Start at the beginning of the next page */
poff = 0;
++page;
cnt += plen;
sglen -= plen;
}
}
}
/* Return the amount actually transferred */
return cnt;
}
/* 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 index = 0, offset = 0;
usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
TO_XFER_BUF);
if (buflen < srb->request_bufflen)
srb->resid = srb->request_bufflen - buflen;
}

View File

@@ -0,0 +1,60 @@
/* Driver for USB Mass Storage compliant devices
* Protocol Functions Header File
*
* $Id: protocol.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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_ATAPI_command(struct scsi_cmnd*, struct us_data*);
extern void usb_stor_qic157_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, unsigned int *index,
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

View File

@@ -0,0 +1,498 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
* $Id: scsiglue.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/slab.h>
#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"
/***********************************************************************
* Host functions
***********************************************************************/
static const char* host_info(struct Scsi_Host *host)
{
return "SCSI emulation for USB Mass Storage devices";
}
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;
/*
* The UFI spec treates 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 == US_SC_UFI)
sdev->sdev_target->pdt_1f_for_no_lun = 1;
return 0;
}
static int slave_configure(struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size. Otherwise a data packet
* would end up being short, causing a premature end to the data
* transfer. Since high-speed bulk pipes have a maxpacket size
* of 512, we'll use that as the scsi device queue's DMA alignment
* mask. Guaranteeing proper alignment of the first buffer will
* have the desired effect because, except at the beginning and
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
/* Many devices have trouble transfering 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->flags & US_FL_MAX_SECTORS_64) &&
sdev->request_queue->max_sectors > 64)
blk_queue_max_sectors(sdev->request_queue, 64);
/* 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) {
/* Disk-type devices use MODE SENSE(6) if the protocol
* (SubClass) is Transparent SCSI, otherwise they use
* MODE SENSE(10). */
if (us->subclass != US_SC_SCSI)
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->flags & 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 disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */
if (us->flags & US_FL_FIX_CAPACITY)
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->flags & US_FL_CAPACITY_HEURISTICS)
sdev->guess_capacity = 1;
/* Some devices report a SCSI revision level above 2 but are
* unable to handle the REPORT LUNS command (for which
* support is mandatory at level 3). Since we already have
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
if (sdev->scsi_level > SCSI_2)
sdev->sdev_target->scsi_level =
sdev->scsi_level = SCSI_2;
/* 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;
} 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;
}
/* 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 == US_PR_CB || us->protocol == US_PR_CBI) &&
sdev->scsi_level == SCSI_UNKNOWN)
us->max_lun = 0;
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command, so suppress those commands. */
if (us->flags & US_FL_NOT_LOCKABLE)
sdev->lockable = 0;
/* this is to satisfy the compiler, tho I don't think the
* return code is ever checked anywhere. */
return 0;
}
/* queue a command */
/* This is always called with scsi_lock(host) held */
static int queuecommand(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
US_DEBUGP("%s called\n", __FUNCTION__);
/* check for state-transition errors */
if (us->srb != NULL) {
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
__FUNCTION__, us->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
/* fail the command if we are disconnecting */
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Fail command during disconnect\n");
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;
up(&(us->sema));
return 0;
}
/***********************************************************************
* 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);
US_DEBUGP("%s called\n", __FUNCTION__);
/* 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));
US_DEBUGP ("-- 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->flags);
if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
set_bit(US_FLIDX_ABORTING, &us->flags);
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;
US_DEBUGP("%s called\n", __FUNCTION__);
/* 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;
US_DEBUGP("%s called\n", __FUNCTION__);
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->flags & 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 own the SCSI host lock. */
void usb_stor_report_bus_reset(struct us_data *us)
{
scsi_report_bus_reset(us_to_host(us), 0);
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
/* we use this macro to help us write into the buffer */
#undef SPRINTF
#define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
static int proc_info (struct Scsi_Host *host, char *buffer,
char **start, off_t offset, int length, int inout)
{
struct us_data *us = host_to_us(host);
char *pos = buffer;
const char *string;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* print the controller name */
SPRINTF(" Host scsi%d: usb-storage\n", host->host_no);
/* 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 */
if (pos < buffer + length) {
pos += sprintf(pos, " Quirks:");
#define US_FLAG(name, value) \
if (us->flags & value) pos += sprintf(pos, " " #name);
US_DO_ALL_FLAGS
#undef US_FLAG
*(pos++) = '\n';
}
/*
* Calculate start of next buffer, and return value.
*/
*start = buffer + offset;
if ((pos - buffer) < offset)
return (0);
else if ((pos - buffer - offset) < length)
return (pos - buffer - offset);
else
return (length);
}
/***********************************************************************
* Sysfs interface
***********************************************************************/
/* Output routine for the sysfs max_sectors file */
static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
return sprintf(buf, "%u\n", sdev->request_queue->max_sectors);
}
/* Input routine for the sysfs max_sectors file */
static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
unsigned short ms;
if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
blk_queue_max_sectors(sdev->request_queue, ms);
return strlen(buf);
}
return -EINVAL;
}
static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
store_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",
.proc_info = proc_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,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL,
/* 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 */
};

View File

@@ -0,0 +1,50 @@
/* Driver for USB Mass Storage compliant devices
* SCSI Connecting Glue Header File
*
* $Id: scsiglue.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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

1653
drivers/usb/storage/sddr09.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/* Driver for SanDisk SDDR-09 SmartMedia reader
* Header File
*
* $Id: sddr09.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
* (c) 2002 Andries Brouwer (aeb@cwi.nl)
*
* See sddr09.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_SHUTTLE_EUSB_SDDR09_H
#define _USB_SHUTTLE_EUSB_SDDR09_H
/* Sandisk SDDR-09 stuff */
extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
extern int usb_stor_sddr09_dpcm_init(struct us_data *us);
extern int usb_stor_sddr09_init(struct us_data *us);
#endif

View File

@@ -0,0 +1,929 @@
/* Driver for SanDisk SDDR-55 SmartMedia reader
*
* $Id: sddr55.c,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* SDDR55 driver v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2002 Simon Munton
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/jiffies.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
#include "sddr55.h"
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
#define PAGESIZE 512
#define set_sense_info(sk, asc, ascq) \
do { \
info->sense_data[2] = sk; \
info->sense_data[12] = asc; \
info->sense_data[13] = ascq; \
} while (0)
struct sddr55_card_info {
unsigned long capacity; /* Size of card in bytes */
int max_log_blks; /* maximum number of logical blocks */
int pageshift; /* log2 of pagesize */
int smallpageshift; /* 1 if pagesize == 256 */
int blocksize; /* Size of block in pages */
int blockshift; /* log2 of blocksize */
int blockmask; /* 2^blockshift - 1 */
int read_only; /* non zero if card is write protected */
int force_read_only; /* non zero if we find a map error*/
int *lba_to_pba; /* logical to physical map */
int *pba_to_lba; /* physical to logical map */
int fatal_error; /* set if we detect something nasty */
unsigned long last_access; /* number of jiffies since we last talked to device */
unsigned char sense_data[18];
};
#define NOT_ALLOCATED 0xffffffff
#define BAD_BLOCK 0xffff
#define CIS_BLOCK 0x400
#define UNUSED_BLOCK 0x3ff
static int
sddr55_bulk_transport(struct us_data *us, int direction,
unsigned char *data, unsigned int len) {
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
us->recv_bulk_pipe : us->send_bulk_pipe;
if (!len)
return USB_STOR_XFER_GOOD;
info->last_access = jiffies;
return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL);
}
/* check if card inserted, if there is, update read_only status
* return non zero if no card
*/
static int sddr55_status(struct us_data *us)
{
int result;
unsigned char *command = us->iobuf;
unsigned char *status = us->iobuf;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
/* send command */
memset(command, 0, 8);
command[5] = 0xB0;
command[7] = 0x80;
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
US_DEBUGP("Result for send_command in status %d\n",
result);
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return USB_STOR_TRANSPORT_ERROR;
}
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, status, 4);
/* expect to get short transfer if no card fitted */
if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
/* had a short transfer, no card inserted, free map memory */
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
info->lba_to_pba = NULL;
info->pba_to_lba = NULL;
info->fatal_error = 0;
info->force_read_only = 0;
set_sense_info (2, 0x3a, 0); /* not ready, medium not present */
return USB_STOR_TRANSPORT_FAILED;
}
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
return USB_STOR_TRANSPORT_FAILED;
}
/* check write protect status */
info->read_only = (status[0] & 0x20);
/* now read status */
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, status, 2);
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
}
return (result == USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_FAILED);
}
static int sddr55_read_data(struct us_data *us,
unsigned int lba,
unsigned int page,
unsigned short sectors) {
int result = USB_STOR_TRANSPORT_GOOD;
unsigned char *command = us->iobuf;
unsigned char *status = us->iobuf;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
unsigned char *buffer;
unsigned int pba;
unsigned long address;
unsigned short pages;
unsigned int len, index, offset;
// Since we only read in one block at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
info->smallpageshift) * PAGESIZE;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR; /* out of memory */
index = offset = 0;
while (sectors>0) {
/* have we got to end? */
if (lba >= info->max_log_blks)
break;
pba = info->lba_to_pba[lba];
// Read as many sectors as possible in this block
pages = min((unsigned int) sectors << info->smallpageshift,
info->blocksize - page);
len = pages << info->pageshift;
US_DEBUGP("Read %02X pages, from PBA %04X"
" (LBA %04X) page %02X\n",
pages, pba, lba, page);
if (pba == NOT_ALLOCATED) {
/* no pba for this lba, fill with zeroes */
memset (buffer, 0, len);
} else {
address = (pba << info->blockshift) + page;
command[0] = 0;
command[1] = LSB_of(address>>16);
command[2] = LSB_of(address>>8);
command[3] = LSB_of(address);
command[4] = 0;
command[5] = 0xB0;
command[6] = LSB_of(pages << (1 - info->smallpageshift));
command[7] = 0x85;
/* send command */
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
US_DEBUGP("Result for send_command in read_data %d\n",
result);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* read data */
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, buffer, len);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* now read status */
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, status, 2);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
/* check status for error */
if (status[0] == 0xff && status[1] == 0x4) {
set_sense_info (3, 0x11, 0);
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
}
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
&index, &offset, TO_XFER_BUF);
page = 0;
lba++;
sectors -= pages >> info->smallpageshift;
}
result = USB_STOR_TRANSPORT_GOOD;
leave:
kfree(buffer);
return result;
}
static int sddr55_write_data(struct us_data *us,
unsigned int lba,
unsigned int page,
unsigned short sectors) {
int result = USB_STOR_TRANSPORT_GOOD;
unsigned char *command = us->iobuf;
unsigned char *status = us->iobuf;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
unsigned char *buffer;
unsigned int pba;
unsigned int new_pba;
unsigned long address;
unsigned short pages;
int i;
unsigned int len, index, offset;
/* check if we are allowed to write */
if (info->read_only || info->force_read_only) {
set_sense_info (7, 0x27, 0); /* read only */
return USB_STOR_TRANSPORT_FAILED;
}
// Since we only write one block at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
// bounce buffer and the actual transfer buffer.
len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
info->smallpageshift) * PAGESIZE;
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
index = offset = 0;
while (sectors > 0) {
/* have we got to end? */
if (lba >= info->max_log_blks)
break;
pba = info->lba_to_pba[lba];
// Write as many sectors as possible in this block
pages = min((unsigned int) sectors << info->smallpageshift,
info->blocksize - page);
len = pages << info->pageshift;
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
&index, &offset, FROM_XFER_BUF);
US_DEBUGP("Write %02X pages, to PBA %04X"
" (LBA %04X) page %02X\n",
pages, pba, lba, page);
command[4] = 0;
if (pba == NOT_ALLOCATED) {
/* no pba allocated for this lba, find a free pba to use */
int max_pba = (info->max_log_blks / 250 ) * 256;
int found_count = 0;
int found_pba = -1;
/* set pba to first block in zone lba is in */
pba = (lba / 1000) * 1024;
US_DEBUGP("No PBA for LBA %04X\n",lba);
if (max_pba > 1024)
max_pba = 1024;
/*
* Scan through the map looking for an unused block
* leave 16 unused blocks at start (or as many as
* possible) since the sddr55 seems to reuse a used
* block when it shouldn't if we don't leave space.
*/
for (i = 0; i < max_pba; i++, pba++) {
if (info->pba_to_lba[pba] == UNUSED_BLOCK) {
found_pba = pba;
if (found_count++ > 16)
break;
}
}
pba = found_pba;
if (pba == -1) {
/* oh dear */
US_DEBUGP("Couldn't find unallocated block\n");
set_sense_info (3, 0x31, 0); /* medium error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba);
/* set writing to unallocated block flag */
command[4] = 0x40;
}
address = (pba << info->blockshift) + page;
command[1] = LSB_of(address>>16);
command[2] = LSB_of(address>>8);
command[3] = LSB_of(address);
/* set the lba into the command, modulo 1000 */
command[0] = LSB_of(lba % 1000);
command[6] = MSB_of(lba % 1000);
command[4] |= LSB_of(pages >> info->smallpageshift);
command[5] = 0xB0;
command[7] = 0x86;
/* send command */
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for send_command in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
/* send the data */
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, buffer, len);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for send_data in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
/* now read status */
result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for get_status in write_data %d\n",
result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
new_pba = (status[3] + (status[4] << 8) + (status[5] << 16))
>> info->blockshift;
/* check status for error */
if (status[0] == 0xff && status[1] == 0x4) {
info->pba_to_lba[new_pba] = BAD_BLOCK;
set_sense_info (3, 0x0c, 0);
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
lba, pba, new_pba);
/* update the lba<->pba maps, note new_pba might be the same as pba */
info->lba_to_pba[lba] = new_pba;
info->pba_to_lba[pba] = UNUSED_BLOCK;
/* check that new_pba wasn't already being used */
if (info->pba_to_lba[new_pba] != UNUSED_BLOCK) {
printk(KERN_ERR "sddr55 error: new PBA %04X already in use for LBA %04X\n",
new_pba, info->pba_to_lba[new_pba]);
info->fatal_error = 1;
set_sense_info (3, 0x31, 0);
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
/* update the pba<->lba maps for new_pba */
info->pba_to_lba[new_pba] = lba % 1000;
page = 0;
lba++;
sectors -= pages >> info->smallpageshift;
}
result = USB_STOR_TRANSPORT_GOOD;
leave:
kfree(buffer);
return result;
}
static int sddr55_read_deviceID(struct us_data *us,
unsigned char *manufacturerID,
unsigned char *deviceID) {
int result;
unsigned char *command = us->iobuf;
unsigned char *content = us->iobuf;
memset(command, 0, 8);
command[5] = 0xB0;
command[7] = 0x84;
result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
US_DEBUGP("Result of send_control for device ID is %d\n",
result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, content, 4);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
*manufacturerID = content[0];
*deviceID = content[1];
if (content[0] != 0xff) {
result = sddr55_bulk_transport(us,
DMA_FROM_DEVICE, content, 2);
}
return USB_STOR_TRANSPORT_GOOD;
}
int sddr55_reset(struct us_data *us) {
return 0;
}
static unsigned long sddr55_get_capacity(struct us_data *us) {
unsigned char manufacturerID;
unsigned char deviceID;
int result;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
US_DEBUGP("Reading capacity...\n");
result = sddr55_read_deviceID(us,
&manufacturerID,
&deviceID);
US_DEBUGP("Result of read_deviceID is %d\n",
result);
if (result != USB_STOR_XFER_GOOD)
return 0;
US_DEBUGP("Device ID = %02X\n", deviceID);
US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
info->pageshift = 9;
info->smallpageshift = 0;
info->blocksize = 16;
info->blockshift = 4;
info->blockmask = 15;
switch (deviceID) {
case 0x6e: // 1MB
case 0xe8:
case 0xec:
info->pageshift = 8;
info->smallpageshift = 1;
return 0x00100000;
case 0xea: // 2MB
case 0x64:
info->pageshift = 8;
info->smallpageshift = 1;
case 0x5d: // 5d is a ROM card with pagesize 512.
return 0x00200000;
case 0xe3: // 4MB
case 0xe5:
case 0x6b:
case 0xd5:
return 0x00400000;
case 0xe6: // 8MB
case 0xd6:
return 0x00800000;
case 0x73: // 16MB
info->blocksize = 32;
info->blockshift = 5;
info->blockmask = 31;
return 0x01000000;
case 0x75: // 32MB
info->blocksize = 32;
info->blockshift = 5;
info->blockmask = 31;
return 0x02000000;
case 0x76: // 64MB
info->blocksize = 32;
info->blockshift = 5;
info->blockmask = 31;
return 0x04000000;
case 0x79: // 128MB
info->blocksize = 32;
info->blockshift = 5;
info->blockmask = 31;
return 0x08000000;
default: // unknown
return 0;
}
}
static int sddr55_read_map(struct us_data *us) {
struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra);
int numblocks;
unsigned char *buffer;
unsigned char *command = us->iobuf;
int i;
unsigned short lba;
unsigned short max_lba;
int result;
if (!info->capacity)
return -1;
numblocks = info->capacity >> (info->blockshift + info->pageshift);
buffer = kmalloc( numblocks * 2, GFP_NOIO );
if (!buffer)
return -1;
memset(command, 0, 8);
command[5] = 0xB0;
command[6] = numblocks * 2 / 256;
command[7] = 0x8A;
result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2);
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2);
if ( result != USB_STOR_XFER_GOOD) {
kfree (buffer);
return -1;
}
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
info->lba_to_pba = NULL;
info->pba_to_lba = NULL;
kfree(buffer);
return -1;
}
memset(info->lba_to_pba, 0xff, numblocks*sizeof(int));
memset(info->pba_to_lba, 0xff, numblocks*sizeof(int));
/* set maximum lba */
max_lba = info->max_log_blks;
if (max_lba > 1000)
max_lba = 1000;
// Each block is 64 bytes of control data, so block i is located in
// scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
for (i=0; i<numblocks; i++) {
int zone = i / 1024;
lba = short_pack(buffer[i * 2], buffer[i * 2 + 1]);
/* Every 1024 physical blocks ("zone"), the LBA numbers
* go back to zero, but are within a higher
* block of LBA's. Also, there is a maximum of
* 1000 LBA's per zone. In other words, in PBA
* 1024-2047 you will find LBA 0-999 which are
* really LBA 1000-1999. Yes, this wastes 24
* physical blocks per zone. Go figure.
* These devices can have blocks go bad, so there
* are 24 spare blocks to use when blocks do go bad.
*/
/* SDDR55 returns 0xffff for a bad block, and 0x400 for the
* CIS block. (Is this true for cards 8MB or less??)
* Record these in the physical to logical map
*/
info->pba_to_lba[i] = lba;
if (lba >= max_lba) {
continue;
}
if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED &&
!info->force_read_only) {
printk("sddr55: map inconsistency at LBA %04X\n", lba + zone * 1000);
info->force_read_only = 1;
}
if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
info->lba_to_pba[lba + zone * 1000] = i;
}
kfree(buffer);
return 0;
}
static void sddr55_card_info_destructor(void *extra) {
struct sddr55_card_info *info = (struct sddr55_card_info *)extra;
if (!extra)
return;
kfree(info->lba_to_pba);
kfree(info->pba_to_lba);
}
/*
* Transport for the Sandisk SDDR-55
*/
int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result;
static unsigned char inquiry_response[8] = {
0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
};
// write-protected for now, no block descriptor support
static unsigned char mode_page_01[20] = {
0x0, 0x12, 0x00, 0x80, 0x0, 0x0, 0x0, 0x0,
0x01, 0x0A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char *ptr = us->iobuf;
unsigned long capacity;
unsigned int lba;
unsigned int pba;
unsigned int page;
unsigned short pages;
struct sddr55_card_info *info;
if (!us->extra) {
us->extra = kzalloc(
sizeof(struct sddr55_card_info), GFP_NOIO);
if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
us->extra_destructor = sddr55_card_info_destructor;
}
info = (struct sddr55_card_info *)(us->extra);
if (srb->cmnd[0] == REQUEST_SENSE) {
US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]);
memcpy (ptr, info->sense_data, sizeof info->sense_data);
ptr[0] = 0x70;
ptr[7] = 11;
usb_stor_set_xfer_buf (ptr, sizeof info->sense_data, srb);
memset (info->sense_data, 0, sizeof info->sense_data);
return USB_STOR_TRANSPORT_GOOD;
}
memset (info->sense_data, 0, sizeof info->sense_data);
/* Dummy up a response for INQUIRY since SDDR55 doesn't
respond to INQUIRY commands */
if (srb->cmnd[0] == INQUIRY) {
memcpy(ptr, inquiry_response, 8);
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
}
/* only check card status if the map isn't allocated, ie no card seen yet
* or if it's been over half a second since we last accessed it
*/
if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
/* check to see if a card is fitted */
result = sddr55_status (us);
if (result) {
result = sddr55_status (us);
if (!result) {
set_sense_info (6, 0x28, 0); /* new media, set unit attention, not ready to ready */
}
return USB_STOR_TRANSPORT_FAILED;
}
}
/* if we detected a problem with the map when writing,
don't allow any more access */
if (info->fatal_error) {
set_sense_info (3, 0x31, 0);
return USB_STOR_TRANSPORT_FAILED;
}
if (srb->cmnd[0] == READ_CAPACITY) {
capacity = sddr55_get_capacity(us);
if (!capacity) {
set_sense_info (3, 0x30, 0); /* incompatible medium */
return USB_STOR_TRANSPORT_FAILED;
}
info->capacity = capacity;
/* figure out the maximum logical block number, allowing for
* the fact that only 250 out of every 256 are used */
info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250;
/* Last page in the card, adjust as we only use 250 out of
* every 256 pages */
capacity = (capacity / 256) * 250;
capacity /= PAGESIZE;
capacity--;
((__be32 *) ptr)[0] = cpu_to_be32(capacity);
((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE);
usb_stor_set_xfer_buf(ptr, 8, srb);
sddr55_read_map(us);
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == MODE_SENSE_10) {
memcpy(ptr, mode_page_01, sizeof mode_page_01);
ptr[3] = (info->read_only || info->force_read_only) ? 0x80 : 0;
usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
US_DEBUGP(
"SDDR55: Dummy up request for mode page 1\n");
return USB_STOR_TRANSPORT_GOOD;
} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
US_DEBUGP(
"SDDR55: Dummy up request for all mode pages\n");
return USB_STOR_TRANSPORT_GOOD;
}
set_sense_info (5, 0x24, 0); /* invalid field in command */
return USB_STOR_TRANSPORT_FAILED;
}
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
US_DEBUGP(
"SDDR55: %s medium removal. Not that I can do"
" anything about it...\n",
(srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) {
page = short_pack(srb->cmnd[3], srb->cmnd[2]);
page <<= 16;
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
page <<= info->smallpageshift;
// convert page to block and page-within-block
lba = page >> info->blockshift;
page = page & info->blockmask;
// locate physical block corresponding to logical block
if (lba >= info->max_log_blks) {
US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
"block %04X\n", lba, info->max_log_blks-1);
set_sense_info (5, 0x24, 0); /* invalid field in command */
return USB_STOR_TRANSPORT_FAILED;
}
pba = info->lba_to_pba[lba];
if (srb->cmnd[0] == WRITE_10) {
US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X"
" pages %d\n",
pba, lba, page, pages);
return sddr55_write_data(us, lba, page, pages);
} else {
US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
" pages %d\n",
pba, lba, page, pages);
return sddr55_read_data(us, lba, page, pages);
}
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == START_STOP) {
return USB_STOR_TRANSPORT_GOOD;
}
set_sense_info (5, 0x20, 0); /* illegal command */
return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
}

View File

@@ -0,0 +1,34 @@
/* Driver for SanDisk SDDR-55 SmartMedia reader
* Header File
*
* $Id: sddr55.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* Current development and maintenance by:
* (c) 2002 Simon Munton
*
* See sddr55.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_SHUTTLE_EUSB_SDDR55_H
#define _USB_SHUTTLE_EUSB_SDDR55_H
/* Sandisk SDDR-55 stuff */
extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us);
extern int sddr55_reset(struct us_data *us);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
/* Driver for SCM Microsystems USB-ATAPI cable
* Header File
*
* $Id: shuttle_usbat.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
* (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
*
* See shuttle_usbat.c for more explanation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _USB_SHUTTLE_USBAT_H
#define _USB_SHUTTLE_USBAT_H
/* Supported device types */
#define USBAT_DEV_HP8200 0x01
#define USBAT_DEV_FLASH 0x02
#define USBAT_EPP_PORT 0x10
#define USBAT_EPP_REGISTER 0x30
#define USBAT_ATA 0x40
#define USBAT_ISA 0x50
/* Commands (need to be logically OR'd with an access type */
#define USBAT_CMD_READ_REG 0x00
#define USBAT_CMD_WRITE_REG 0x01
#define USBAT_CMD_READ_BLOCK 0x02
#define USBAT_CMD_WRITE_BLOCK 0x03
#define USBAT_CMD_COND_READ_BLOCK 0x04
#define USBAT_CMD_COND_WRITE_BLOCK 0x05
#define USBAT_CMD_WRITE_REGS 0x07
/* Commands (these don't need an access type) */
#define USBAT_CMD_EXEC_CMD 0x80
#define USBAT_CMD_SET_FEAT 0x81
#define USBAT_CMD_UIO 0x82
/* Methods of accessing UIO register */
#define USBAT_UIO_READ 1
#define USBAT_UIO_WRITE 0
/* Qualifier bits */
#define USBAT_QUAL_FCQ 0x20 /* full compare */
#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */
/* USBAT Flash Media status types */
#define USBAT_FLASH_MEDIA_NONE 0
#define USBAT_FLASH_MEDIA_CF 1
/* USBAT Flash Media change types */
#define USBAT_FLASH_MEDIA_SAME 0
#define USBAT_FLASH_MEDIA_CHANGED 1
/* USBAT ATA registers */
#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */
#define USBAT_ATA_FEATURES 0x11 /* set features (W) */
#define USBAT_ATA_ERROR 0x11 /* error (R) */
#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */
#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */
#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */
#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */
#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */
#define USBAT_ATA_STATUS 0x17 /* device status (R) */
#define USBAT_ATA_CMD 0x17 /* device command (W) */
#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */
/* USBAT User I/O Data registers */
#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */
#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */
/* CDT = ACKD & !UI1 & !UI0 */
#define USBAT_UIO_1 0x20 /* I/O 1 */
#define USBAT_UIO_0 0x10 /* I/O 0 */
#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */
#define USBAT_UIO_UI1 0x04 /* Input 1 */
#define USBAT_UIO_UI0 0x02 /* Input 0 */
#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
/* USBAT User I/O Enable registers */
#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */
#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */
#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */
/* If ACKD=1, set OE1 to 1 also. */
#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */
#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */
/* USBAT Features */
#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */
#define USBAT_FEAT_U1 0x08
#define USBAT_FEAT_U0 0x04
#define USBAT_FEAT_ET1 0x02
#define USBAT_FEAT_ET2 0x01
extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
extern int init_usbat_cd(struct us_data *us);
extern int init_usbat_flash(struct us_data *us);
extern int init_usbat_probe(struct us_data *us);
struct usbat_info {
int devicetype;
/* Used for Flash readers only */
unsigned long sectors; /* total sector count */
unsigned long ssize; /* sector size in bytes */
unsigned char sense_key;
unsigned long sense_asc; /* additional sense code */
unsigned long sense_ascq; /* additional sense code qualifier */
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
/* Driver for USB Mass Storage compliant devices
* Transport Functions Header File
*
* $Id: transport.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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>
/*
* Bulk only data structures
*/
/* command block wrapper */
struct bulk_cb_wrap {
__le32 Signature; /* contains 'USBC' */
__u32 Tag; /* unique per command id */
__le32 DataTransferLength; /* size of data */
__u8 Flags; /* direction in bit 0 */
__u8 Lun; /* LUN normally 0 */
__u8 Length; /* of of the CDB */
__u8 CDB[16]; /* max command */
};
#define US_BULK_CB_WRAP_LEN 31
#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
#define US_BULK_FLAG_IN 1
#define US_BULK_FLAG_OUT 0
/* command status wrapper */
struct bulk_cs_wrap {
__le32 Signature; /* should = 'USBS' */
__u32 Tag; /* same as original command */
__le32 Residue; /* amount not transferred */
__u8 Status; /* see below */
__u8 Filler[18];
};
#define US_BULK_CS_WRAP_LEN 13
#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
#define US_BULK_STAT_OK 0
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
/* bulk-only class specific requests */
#define US_BULK_RESET_REQUEST 0xff
#define US_BULK_GET_MAX_LUN 0xfe
/*
* usb_stor_bulk_transfer_xxx() return codes, in order of severity
*/
#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_CBI_transport(struct scsi_cmnd *, struct us_data*);
extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
extern int usb_stor_CB_reset(struct us_data*);
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_port_reset(struct us_data *us);
#endif

File diff suppressed because it is too large Load Diff

1107
drivers/usb/storage/usb.c Normal file

File diff suppressed because it is too large Load Diff

179
drivers/usb/storage/usb.h Normal file
View File

@@ -0,0 +1,179 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
* $Id: usb.h,v 1.1.1.1 2007/06/12 07:27:09 eyryu Exp $
*
* 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/smp_lock.h>
#include <linux/completion.h>
#include <linux/mutex.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 flag definitions: used in set_bit() etc. */
#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */
#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */
#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */
#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */
#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \
(1UL << US_FLIDX_DISCONNECTING))
#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */
#define US_FLIDX_TIMED_OUT 23 /* 0x00800000 SCSI midlayer timed out */
#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 flags; /* from filter initially */
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 */
/* control and bulk communications data */
struct urb *current_urb; /* USB requests */
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
unsigned char *sensebuf; /* sense data buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
/* mutual exclusion and synchronization structures */
struct semaphore sema; /* to sleep thread on */
struct completion notify; /* thread begin/end */
wait_queue_head_t delay_wait; /* wait during scan, reset */
/* subdriver information */
void *extra; /* Any extra data */
extra_data_destructor extra_destructor;/* extra data destructor */
#ifdef CONFIG_PM
pm_hook suspend_resume_hook;
#endif
};
/* 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)
#endif