2005-09-30 15:49:36 +04:00
/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
2005-04-17 02:20:36 +04:00
*
* Current development and maintenance by :
* ( c ) 2000 , 2001 Robert Baruch ( autophile @ starband . net )
* ( c ) 2004 , 2005 Daniel Drake < dsd @ gentoo . org >
*
* Developed with the assistance of :
* ( c ) 2002 Alan Stern < stern @ rowland . org >
*
* Flash support based on earlier work by :
* ( c ) 2002 Thomas Kreiling < usbdev @ sm04 . de >
*
* Many originally ATAPI devices were slightly modified to meet the USB
* market by using some kind of translation from ATAPI to USB on the host ,
* and the peripheral would translate from USB back to ATAPI .
*
* SCM Microsystems ( www . scmmicro . com ) makes a device , sold to OEM ' s only ,
* which does the USB - to - ATAPI conversion . By obtaining the data sheet on
* their device under nondisclosure agreement , I have been able to write
* this driver for Linux .
*
* The chip used in the device can also be used for EPP and ISA translation
* as well . This driver is only guaranteed to work with the ATAPI
* translation .
*
* See the Kconfig help text for a list of devices known to be supported by
* 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 0213 9 , USA .
*/
# include <linux/errno.h>
2009-02-12 22:48:08 +03:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/cdrom.h>
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include "usb.h"
# include "transport.h"
# include "protocol.h"
# include "debug.h"
2009-02-12 22:48:08 +03:00
2009-02-28 23:39:20 +03:00
MODULE_DESCRIPTION ( " Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable " ) ;
MODULE_AUTHOR ( " Daniel Drake <dsd@gentoo.org>, Robert Baruch <autophile@starband.net> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-02-12 22:48:08 +03:00
/* Supported device types */
# define USBAT_DEV_HP8200 0x01
# define USBAT_DEV_FLASH 0x02
# define USBAT_EPP_PORT 0x10
# define USBAT_EPP_REGISTER 0x30
# define USBAT_ATA 0x40
# define USBAT_ISA 0x50
/* Commands (need to be logically OR'd with an access type */
# define USBAT_CMD_READ_REG 0x00
# define USBAT_CMD_WRITE_REG 0x01
# define USBAT_CMD_READ_BLOCK 0x02
# define USBAT_CMD_WRITE_BLOCK 0x03
# define USBAT_CMD_COND_READ_BLOCK 0x04
# define USBAT_CMD_COND_WRITE_BLOCK 0x05
# define USBAT_CMD_WRITE_REGS 0x07
/* Commands (these don't need an access type) */
# define USBAT_CMD_EXEC_CMD 0x80
# define USBAT_CMD_SET_FEAT 0x81
# define USBAT_CMD_UIO 0x82
/* Methods of accessing UIO register */
# define USBAT_UIO_READ 1
# define USBAT_UIO_WRITE 0
/* Qualifier bits */
# define USBAT_QUAL_FCQ 0x20 /* full compare */
# define USBAT_QUAL_ALQ 0x10 /* auto load subcount */
/* USBAT Flash Media status types */
# define USBAT_FLASH_MEDIA_NONE 0
# define USBAT_FLASH_MEDIA_CF 1
/* USBAT Flash Media change types */
# define USBAT_FLASH_MEDIA_SAME 0
# define USBAT_FLASH_MEDIA_CHANGED 1
/* USBAT ATA registers */
# define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */
# define USBAT_ATA_FEATURES 0x11 /* set features (W) */
# define USBAT_ATA_ERROR 0x11 /* error (R) */
# define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */
# define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */
# define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */
# define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */
# define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */
# define USBAT_ATA_STATUS 0x17 /* device status (R) */
# define USBAT_ATA_CMD 0x17 /* device command (W) */
# define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */
/* USBAT User I/O Data registers */
# define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */
# define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */
/* CDT = ACKD & !UI1 & !UI0 */
# define USBAT_UIO_1 0x20 /* I/O 1 */
# define USBAT_UIO_0 0x10 /* I/O 0 */
# define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */
# define USBAT_UIO_UI1 0x04 /* Input 1 */
# define USBAT_UIO_UI0 0x02 /* Input 0 */
# define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
/* USBAT User I/O Enable registers */
# define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */
# define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */
# define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */
/* If ACKD=1, set OE1 to 1 also. */
# define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */
# define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */
/* USBAT Features */
# define USBAT_FEAT_ETEN 0x80 /* External trigger enable */
# define USBAT_FEAT_U1 0x08
# define USBAT_FEAT_U0 0x04
# define USBAT_FEAT_ET1 0x02
# define USBAT_FEAT_ET2 0x01
struct usbat_info {
int devicetype ;
/* Used for Flash readers only */
unsigned long sectors ; /* total sector count */
unsigned long ssize ; /* sector size in bytes */
unsigned char sense_key ;
unsigned long sense_asc ; /* additional sense code */
unsigned long sense_ascq ; /* additional sense code qualifier */
} ;
2005-04-17 02:20:36 +04:00
# define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
# define LSB_of(s) ((s)&0xFF)
# define MSB_of(s) ((s)>>8)
static int transferred = 0 ;
static int usbat_flash_transport ( struct scsi_cmnd * srb , struct us_data * us ) ;
static int usbat_hp8200e_transport ( struct scsi_cmnd * srb , struct us_data * us ) ;
2009-02-12 22:48:08 +03:00
static int init_usbat_cd ( struct us_data * us ) ;
static int init_usbat_flash ( struct us_data * us ) ;
/*
* The table of devices
*/
# define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName , productName , useProtocol , useTransport , \
initFunction , flags ) \
{ USB_DEVICE_VER ( id_vendor , id_product , bcdDeviceMin , bcdDeviceMax ) , \
2012-08-29 00:37:13 +04:00
. driver_info = ( flags ) }
2009-02-12 22:48:08 +03:00
2011-11-15 11:53:40 +04:00
static struct usb_device_id usbat_usb_ids [ ] = {
2009-02-12 22:48:08 +03:00
# include "unusual_usbat.h"
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , usbat_usb_ids ) ;
# undef UNUSUAL_DEV
/*
* The flags table
*/
# define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name , product_name , use_protocol , use_transport , \
init_function , Flags ) \
{ \
. vendorName = vendor_name , \
. productName = product_name , \
. useProtocol = use_protocol , \
. useTransport = use_transport , \
. initFunction = init_function , \
}
static struct us_unusual_dev usbat_unusual_dev_list [ ] = {
# include "unusual_usbat.h"
{ } /* Terminating entry */
} ;
# undef UNUSUAL_DEV
2005-04-17 02:20:36 +04:00
/*
2005-09-30 15:49:36 +04:00
* Convenience function to produce an ATA read / write sectors command
2005-04-17 02:20:36 +04:00
* Use cmd = 0x20 for read , cmd = 0x30 for write
*/
2005-09-30 15:49:36 +04:00
static void usbat_pack_ata_sector_cmd ( unsigned char * buf ,
2005-04-17 02:20:36 +04:00
unsigned char thistime ,
u32 sector , unsigned char cmd )
{
buf [ 0 ] = 0 ;
buf [ 1 ] = thistime ;
buf [ 2 ] = sector & 0xFF ;
buf [ 3 ] = ( sector > > 8 ) & 0xFF ;
buf [ 4 ] = ( sector > > 16 ) & 0xFF ;
buf [ 5 ] = 0xE0 | ( ( sector > > 24 ) & 0x0F ) ;
buf [ 6 ] = cmd ;
}
/*
* Convenience function to get the device type ( flash or hp8200 )
*/
static int usbat_get_device_type ( struct us_data * us )
{
return ( ( struct usbat_info * ) us - > extra ) - > devicetype ;
}
/*
* Read a register from the device
*/
static int usbat_read ( struct us_data * us ,
unsigned char access ,
unsigned char reg ,
unsigned char * content )
{
return usb_stor_ctrl_transfer ( us ,
us - > recv_ctrl_pipe ,
access | USBAT_CMD_READ_REG ,
0xC0 ,
( u16 ) reg ,
0 ,
content ,
1 ) ;
}
/*
* Write to a register on the device
*/
static int usbat_write ( struct us_data * us ,
unsigned char access ,
unsigned char reg ,
unsigned char content )
{
return usb_stor_ctrl_transfer ( us ,
us - > send_ctrl_pipe ,
access | USBAT_CMD_WRITE_REG ,
0x40 ,
short_pack ( reg , content ) ,
0 ,
NULL ,
0 ) ;
}
/*
* Convenience function to perform a bulk read
*/
static int usbat_bulk_read ( struct us_data * us ,
2007-09-09 21:40:56 +04:00
void * buf ,
2006-05-02 21:30:12 +04:00
unsigned int len ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
if ( len = = 0 )
return USB_STOR_XFER_GOOD ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " len = %d \n " , len ) ;
2007-09-09 21:40:56 +04:00
return usb_stor_bulk_transfer_sg ( us , us - > recv_bulk_pipe , buf , len , use_sg , NULL ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Convenience function to perform a bulk write
*/
static int usbat_bulk_write ( struct us_data * us ,
2007-09-09 21:40:56 +04:00
void * buf ,
2006-05-02 21:30:12 +04:00
unsigned int len ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
if ( len = = 0 )
return USB_STOR_XFER_GOOD ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " len = %d \n " , len ) ;
2007-09-09 21:40:56 +04:00
return usb_stor_bulk_transfer_sg ( us , us - > send_bulk_pipe , buf , len , use_sg , NULL ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Some USBAT - specific commands can only be executed over a command transport
* This transport allows one ( len = 8 ) or two ( len = 16 ) vendor - specific commands
* to be executed .
*/
static int usbat_execute_command ( struct us_data * us ,
unsigned char * commands ,
unsigned int len )
{
return usb_stor_ctrl_transfer ( us , us - > send_ctrl_pipe ,
USBAT_CMD_EXEC_CMD , 0x40 , 0 , 0 ,
commands , len ) ;
}
/*
* Read the status register
*/
static int usbat_get_status ( struct us_data * us , unsigned char * status )
{
int rc ;
rc = usbat_read ( us , USBAT_ATA , USBAT_ATA_STATUS , status ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " 0x%02X \n " , * status ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
/*
* Check the device status
*/
static int usbat_check_status ( struct us_data * us )
{
unsigned char * reply = us - > iobuf ;
int rc ;
rc = usbat_get_status ( us , reply ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
/* error/check condition (0x51 is ok) */
if ( * reply & 0x01 & & * reply ! = 0x51 )
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
/* device fault */
if ( * reply & 0x20 )
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
return USB_STOR_TRANSPORT_GOOD ;
}
/*
2011-03-31 05:57:33 +04:00
* Stores critical information in internal registers in preparation for the execution
2005-04-17 02:20:36 +04:00
* of a conditional usbat_read_blocks or usbat_write_blocks call .
*/
static int usbat_set_shuttle_features ( struct us_data * us ,
unsigned char external_trigger ,
unsigned char epp_control ,
unsigned char mask_byte ,
unsigned char test_pattern ,
unsigned char subcountH ,
unsigned char subcountL )
{
unsigned char * command = us - > iobuf ;
command [ 0 ] = 0x40 ;
command [ 1 ] = USBAT_CMD_SET_FEAT ;
2005-09-30 15:49:36 +04:00
/*
* The only bit relevant to ATA access is bit 6
* which defines 8 bit data access ( set ) or 16 bit ( unset )
*/
2005-04-17 02:20:36 +04:00
command [ 2 ] = epp_control ;
2005-09-30 15:49:36 +04:00
/*
* If FCQ is set in the qualifier ( defined in R / W cmd ) , then bits U0 , U1 ,
* ET1 and ET2 define an external event to be checked for on event of a
* _read_blocks or _write_blocks operation . The read / write will not take
* place unless the defined trigger signal is active .
*/
2005-04-17 02:20:36 +04:00
command [ 3 ] = external_trigger ;
2005-09-30 15:49:36 +04:00
/*
* The resultant byte of the mask operation ( see mask_byte ) is compared for
* equivalence with this test pattern . If equal , the read / write will take
* place .
*/
2005-04-17 02:20:36 +04:00
command [ 4 ] = test_pattern ;
2005-09-30 15:49:36 +04:00
/*
* This value is logically ANDed with the status register field specified
* in the read / write command .
*/
2005-04-17 02:20:36 +04:00
command [ 5 ] = mask_byte ;
2005-09-30 15:49:36 +04:00
/*
* If ALQ is set in the qualifier , this field contains the address of the
* registers where the byte count should be read for transferring the data .
* If ALQ is not set , then this field contains the number of bytes to be
* transferred .
*/
2005-04-17 02:20:36 +04:00
command [ 6 ] = subcountL ;
command [ 7 ] = subcountH ;
return usbat_execute_command ( us , command , 8 ) ;
}
/*
* Block , waiting for an ATA device to become not busy or to report
* an error condition .
*/
static int usbat_wait_not_busy ( struct us_data * us , int minutes )
{
int i ;
int result ;
unsigned char * status = us - > iobuf ;
/* Synchronizing cache on a CDR could take a heck of a long time,
* but probably not more than 10 minutes or so . On the other hand ,
* doing a full blank on a CDRW at speed 1 will take about 75
* minutes !
*/
for ( i = 0 ; i < 1200 + minutes * 60 ; i + + ) {
result = usbat_get_status ( us , status ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
if ( * status & 0x01 ) { /* check condition */
2005-04-17 02:20:36 +04:00
result = usbat_read ( us , USBAT_ATA , 0x10 , status ) ;
return USB_STOR_TRANSPORT_FAILED ;
}
2005-09-30 15:49:36 +04:00
if ( * status & 0x20 ) /* device fault */
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
if ( ( * status & 0x80 ) = = 0x00 ) { /* not busy */
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Waited not busy for %d steps \n " , i ) ;
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_GOOD ;
}
if ( i < 500 )
2005-09-30 15:49:36 +04:00
msleep ( 10 ) ; /* 5 seconds */
2005-04-17 02:20:36 +04:00
else if ( i < 700 )
2005-09-30 15:49:36 +04:00
msleep ( 50 ) ; /* 10 seconds */
2005-04-17 02:20:36 +04:00
else if ( i < 1200 )
2005-09-30 15:49:36 +04:00
msleep ( 100 ) ; /* 50 seconds */
2005-04-17 02:20:36 +04:00
else
2005-09-30 15:49:36 +04:00
msleep ( 1000 ) ; /* X minutes */
2005-04-17 02:20:36 +04:00
}
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Waited not busy for %d minutes, timing out \n " ,
minutes ) ;
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
}
/*
* Read block data from the data register
*/
static int usbat_read_block ( struct us_data * us ,
2007-09-09 21:40:56 +04:00
void * buf ,
2006-05-02 21:30:12 +04:00
unsigned short len ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
int result ;
unsigned char * command = us - > iobuf ;
if ( ! len )
return USB_STOR_TRANSPORT_GOOD ;
command [ 0 ] = 0xC0 ;
command [ 1 ] = USBAT_ATA | USBAT_CMD_READ_BLOCK ;
command [ 2 ] = USBAT_ATA_DATA ;
command [ 3 ] = 0 ;
command [ 4 ] = 0 ;
command [ 5 ] = 0 ;
command [ 6 ] = LSB_of ( len ) ;
command [ 7 ] = MSB_of ( len ) ;
result = usbat_execute_command ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2007-09-09 21:40:56 +04:00
result = usbat_bulk_read ( us , buf , len , use_sg ) ;
2005-04-17 02:20:36 +04:00
return ( result = = USB_STOR_XFER_GOOD ?
USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR ) ;
}
/*
* Write block data via the data register
*/
static int usbat_write_block ( struct us_data * us ,
unsigned char access ,
2007-09-09 21:40:56 +04:00
void * buf ,
2005-04-17 02:20:36 +04:00
unsigned short len ,
2006-05-02 21:30:12 +04:00
int minutes ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
int result ;
unsigned char * command = us - > iobuf ;
if ( ! len )
return USB_STOR_TRANSPORT_GOOD ;
command [ 0 ] = 0x40 ;
command [ 1 ] = access | USBAT_CMD_WRITE_BLOCK ;
command [ 2 ] = USBAT_ATA_DATA ;
command [ 3 ] = 0 ;
command [ 4 ] = 0 ;
command [ 5 ] = 0 ;
command [ 6 ] = LSB_of ( len ) ;
command [ 7 ] = MSB_of ( len ) ;
result = usbat_execute_command ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2007-09-09 21:40:56 +04:00
result = usbat_bulk_write ( us , buf , len , use_sg ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
return usbat_wait_not_busy ( us , minutes ) ;
}
/*
* Process read and write requests
*/
static int usbat_hp8200e_rw_block_test ( struct us_data * us ,
unsigned char access ,
unsigned char * registers ,
unsigned char * data_out ,
unsigned short num_registers ,
unsigned char data_reg ,
unsigned char status_reg ,
unsigned char timeout ,
unsigned char qualifier ,
int direction ,
2007-09-09 21:40:56 +04:00
void * buf ,
2005-04-17 02:20:36 +04:00
unsigned short len ,
int use_sg ,
int minutes )
{
int result ;
unsigned int pipe = ( direction = = DMA_FROM_DEVICE ) ?
us - > recv_bulk_pipe : us - > send_bulk_pipe ;
unsigned char * command = us - > iobuf ;
int i , j ;
int cmdlen ;
unsigned char * data = us - > iobuf ;
unsigned char * status = us - > iobuf ;
BUG_ON ( num_registers > US_IOBUF_SIZE / 2 ) ;
for ( i = 0 ; i < 20 ; i + + ) {
/*
* The first time we send the full command , which consists
* of downloading the SCSI command followed by downloading
* the data via a write - and - test . Any other time we only
* send the command to download the data - - the SCSI command
* is still ' active ' in some sense in the device .
*
* We ' re only going to try sending the data 10 times . After
* that , we just return a failure .
*/
if ( i = = 0 ) {
cmdlen = 16 ;
2005-09-30 15:49:36 +04:00
/*
* Write to multiple registers
* Not really sure the 0x07 , 0x17 , 0xfc , 0xe7 is
* necessary here , but that ' s what came out of the
* trace every single time .
*/
2005-04-17 02:20:36 +04:00
command [ 0 ] = 0x40 ;
command [ 1 ] = access | USBAT_CMD_WRITE_REGS ;
command [ 2 ] = 0x07 ;
command [ 3 ] = 0x17 ;
command [ 4 ] = 0xFC ;
command [ 5 ] = 0xE7 ;
command [ 6 ] = LSB_of ( num_registers * 2 ) ;
command [ 7 ] = MSB_of ( num_registers * 2 ) ;
} else
cmdlen = 8 ;
2005-09-30 15:49:36 +04:00
/* Conditionally read or write blocks */
2005-04-17 02:20:36 +04:00
command [ cmdlen - 8 ] = ( direction = = DMA_TO_DEVICE ? 0x40 : 0xC0 ) ;
command [ cmdlen - 7 ] = access |
( direction = = DMA_TO_DEVICE ?
USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK ) ;
command [ cmdlen - 6 ] = data_reg ;
command [ cmdlen - 5 ] = status_reg ;
command [ cmdlen - 4 ] = timeout ;
command [ cmdlen - 3 ] = qualifier ;
command [ cmdlen - 2 ] = LSB_of ( len ) ;
command [ cmdlen - 1 ] = MSB_of ( len ) ;
result = usbat_execute_command ( us , command , cmdlen ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( i = = 0 ) {
for ( j = 0 ; j < num_registers ; j + + ) {
data [ j < < 1 ] = registers [ j ] ;
data [ 1 + ( j < < 1 ) ] = data_out [ j ] ;
}
2006-05-02 21:30:12 +04:00
result = usbat_bulk_write ( us , data , num_registers * 2 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
}
result = usb_stor_bulk_transfer_sg ( us ,
2007-09-09 21:40:56 +04:00
pipe , buf , len , use_sg , NULL ) ;
2005-04-17 02:20:36 +04:00
/*
* If we get a stall on the bulk download , we ' ll retry
* the bulk download - - but not the SCSI command because
* in some sense the SCSI command is still ' active ' and
* waiting for the data . Don ' t ask me why this should be ;
* I ' m only following what the Windoze driver did .
*
* Note that a stall for the test - and - read / write command means
* that the test failed . In this case we ' re testing to make
* sure that the device is error - free
* ( i . e . bit 0 - - CHK - - of status is 0 ) . The most likely
* hypothesis is that the USBAT chip somehow knows what
* the device will accept , but doesn ' t give the device any
* data until all data is received . Thus , the device would
* still be waiting for the first byte of data if a stall
* occurs , even if the stall implies that some data was
* transferred .
*/
if ( result = = USB_STOR_XFER_SHORT | |
result = = USB_STOR_XFER_STALLED ) {
/*
* If we ' re reading and we stalled , then clear
* the bulk output pipe only the first time .
*/
if ( direction = = DMA_FROM_DEVICE & & i = = 0 ) {
if ( usb_stor_clear_halt ( us ,
us - > send_bulk_pipe ) < 0 )
return USB_STOR_TRANSPORT_ERROR ;
}
/*
* Read status : is the device angry , or just busy ?
*/
result = usbat_read ( us , USBAT_ATA ,
direction = = DMA_TO_DEVICE ?
USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS ,
status ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
if ( * status & 0x01 ) /* check condition */
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
if ( * status & 0x20 ) /* device fault */
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Redoing %s \n " ,
direction = = DMA_TO_DEVICE
? " write " : " read " ) ;
2005-04-17 02:20:36 +04:00
} else if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
else
return usbat_wait_not_busy ( us , minutes ) ;
}
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Bummer! %s bulk data 20 times failed \n " ,
direction = = DMA_TO_DEVICE ? " Writing " : " Reading " ) ;
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
}
/*
* Write to multiple registers :
* Allows us to write specific data to any registers . The data to be written
* gets packed in this sequence : reg0 , data0 , reg1 , data1 , . . . , regN , dataN
* which gets sent through bulk out .
* Not designed for large transfers of data !
*/
static int usbat_multiple_write ( struct us_data * us ,
unsigned char * registers ,
unsigned char * data_out ,
unsigned short num_registers )
{
int i , result ;
unsigned char * data = us - > iobuf ;
unsigned char * command = us - > iobuf ;
BUG_ON ( num_registers > US_IOBUF_SIZE / 2 ) ;
2005-09-30 15:49:36 +04:00
/* Write to multiple registers, ATA access */
2005-04-17 02:20:36 +04:00
command [ 0 ] = 0x40 ;
command [ 1 ] = USBAT_ATA | USBAT_CMD_WRITE_REGS ;
2005-09-30 15:49:36 +04:00
/* No relevance */
2005-04-17 02:20:36 +04:00
command [ 2 ] = 0 ;
command [ 3 ] = 0 ;
command [ 4 ] = 0 ;
command [ 5 ] = 0 ;
2005-09-30 15:49:36 +04:00
/* Number of bytes to be transferred (incl. addresses and data) */
2005-04-17 02:20:36 +04:00
command [ 6 ] = LSB_of ( num_registers * 2 ) ;
command [ 7 ] = MSB_of ( num_registers * 2 ) ;
2005-09-30 15:49:36 +04:00
/* The setup command */
2005-04-17 02:20:36 +04:00
result = usbat_execute_command ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
/* Create the reg/data, reg/data sequence */
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < num_registers ; i + + ) {
data [ i < < 1 ] = registers [ i ] ;
data [ 1 + ( i < < 1 ) ] = data_out [ i ] ;
}
2005-09-30 15:49:36 +04:00
/* Send the data */
2006-05-02 21:30:12 +04:00
result = usbat_bulk_write ( us , data , num_registers * 2 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_get_device_type ( us ) = = USBAT_DEV_HP8200 )
return usbat_wait_not_busy ( us , 0 ) ;
else
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Conditionally read blocks from device :
* Allows us to read blocks from a specific data register , based upon the
* condition that a status register can be successfully masked with a status
* qualifier . If this condition is not initially met , the read will wait
* up until a maximum amount of time has elapsed , as specified by timeout .
* The read will start when the condition is met , otherwise the command aborts .
*
* The qualifier defined here is not the value that is masked , it defines
* conditions for the write to take place . The actual masked qualifier ( and
* other related details ) are defined beforehand with _set_shuttle_features ( ) .
*/
static int usbat_read_blocks ( struct us_data * us ,
2007-09-09 21:40:56 +04:00
void * buffer ,
2006-05-02 21:30:12 +04:00
int len ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
int result ;
unsigned char * command = us - > iobuf ;
command [ 0 ] = 0xC0 ;
command [ 1 ] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK ;
command [ 2 ] = USBAT_ATA_DATA ;
command [ 3 ] = USBAT_ATA_STATUS ;
2005-09-30 15:49:36 +04:00
command [ 4 ] = 0xFD ; /* Timeout (ms); */
2005-04-17 02:20:36 +04:00
command [ 5 ] = USBAT_QUAL_FCQ ;
command [ 6 ] = LSB_of ( len ) ;
command [ 7 ] = MSB_of ( len ) ;
2005-09-30 15:49:36 +04:00
/* Multiple block read setup command */
2005-04-17 02:20:36 +04:00
result = usbat_execute_command ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
/* Read the blocks we just asked for */
2006-05-02 21:30:12 +04:00
result = usbat_bulk_read ( us , buffer , len , use_sg ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_FAILED ;
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Conditionally write blocks to device :
* Allows us to write blocks to a specific data register , based upon the
* condition that a status register can be successfully masked with a status
* qualifier . If this condition is not initially met , the write will wait
* up until a maximum amount of time has elapsed , as specified by timeout .
* The read will start when the condition is met , otherwise the command aborts .
*
* The qualifier defined here is not the value that is masked , it defines
* conditions for the write to take place . The actual masked qualifier ( and
* other related details ) are defined beforehand with _set_shuttle_features ( ) .
*/
static int usbat_write_blocks ( struct us_data * us ,
2007-09-09 21:40:56 +04:00
void * buffer ,
2006-05-02 21:30:12 +04:00
int len ,
int use_sg )
2005-04-17 02:20:36 +04:00
{
int result ;
unsigned char * command = us - > iobuf ;
command [ 0 ] = 0x40 ;
command [ 1 ] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK ;
command [ 2 ] = USBAT_ATA_DATA ;
command [ 3 ] = USBAT_ATA_STATUS ;
2005-09-30 15:49:36 +04:00
command [ 4 ] = 0xFD ; /* Timeout (ms) */
2005-04-17 02:20:36 +04:00
command [ 5 ] = USBAT_QUAL_FCQ ;
command [ 6 ] = LSB_of ( len ) ;
command [ 7 ] = MSB_of ( len ) ;
2005-09-30 15:49:36 +04:00
/* Multiple block write setup command */
2005-04-17 02:20:36 +04:00
result = usbat_execute_command ( us , command , 8 ) ;
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_FAILED ;
2005-09-30 15:49:36 +04:00
/* Write the data */
2006-05-02 21:30:12 +04:00
result = usbat_bulk_write ( us , buffer , len , use_sg ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_FAILED ;
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Read the User IO register
*/
static int usbat_read_user_io ( struct us_data * us , unsigned char * data_flags )
{
int result ;
result = usb_stor_ctrl_transfer ( us ,
us - > recv_ctrl_pipe ,
USBAT_CMD_UIO ,
0xC0 ,
0 ,
0 ,
data_flags ,
USBAT_UIO_READ ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " UIO register reads %02X \n " , * data_flags ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/*
* Write to the User IO register
*/
static int usbat_write_user_io ( struct us_data * us ,
unsigned char enable_flags ,
unsigned char data_flags )
{
return usb_stor_ctrl_transfer ( us ,
us - > send_ctrl_pipe ,
USBAT_CMD_UIO ,
0x40 ,
short_pack ( enable_flags , data_flags ) ,
0 ,
NULL ,
USBAT_UIO_WRITE ) ;
}
/*
* Reset the device
* Often needed on media change .
*/
static int usbat_device_reset ( struct us_data * us )
{
int rc ;
2005-09-30 15:49:36 +04:00
/*
* Reset peripheral , enable peripheral control signals
* ( bring reset signal up )
*/
2005-04-17 02:20:36 +04:00
rc = usbat_write_user_io ( us ,
USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0 ,
USBAT_UIO_EPAD | USBAT_UIO_1 ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
/*
* Enable peripheral control signals
* ( bring reset signal down )
*/
2005-04-17 02:20:36 +04:00
rc = usbat_write_user_io ( us ,
USBAT_UIO_OE1 | USBAT_UIO_OE0 ,
USBAT_UIO_EPAD | USBAT_UIO_1 ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Enable card detect
*/
static int usbat_device_enable_cdt ( struct us_data * us )
{
int rc ;
2005-09-30 15:49:36 +04:00
/* Enable peripheral control signals and card detect */
2005-04-17 02:20:36 +04:00
rc = usbat_write_user_io ( us ,
USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0 ,
USBAT_UIO_EPAD | USBAT_UIO_1 ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Determine if media is present .
*/
2013-04-19 22:44:00 +04:00
static int usbat_flash_check_media_present ( struct us_data * us ,
unsigned char * uio )
2005-04-17 02:20:36 +04:00
{
if ( * uio & USBAT_UIO_UI0 ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " no media detected \n " ) ;
2005-04-17 02:20:36 +04:00
return USBAT_FLASH_MEDIA_NONE ;
}
return USBAT_FLASH_MEDIA_CF ;
}
/*
* Determine if media has changed since last operation
*/
2013-04-19 22:44:00 +04:00
static int usbat_flash_check_media_changed ( struct us_data * us ,
unsigned char * uio )
2005-04-17 02:20:36 +04:00
{
if ( * uio & USBAT_UIO_0 ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " media change detected \n " ) ;
2005-04-17 02:20:36 +04:00
return USBAT_FLASH_MEDIA_CHANGED ;
}
return USBAT_FLASH_MEDIA_SAME ;
}
/*
* Check for media change / no media and handle the situation appropriately
*/
static int usbat_flash_check_media ( struct us_data * us ,
struct usbat_info * info )
{
int rc ;
unsigned char * uio = us - > iobuf ;
rc = usbat_read_user_io ( us , uio ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
/* Check for media existence */
2013-04-19 22:44:00 +04:00
rc = usbat_flash_check_media_present ( us , uio ) ;
2005-04-17 02:20:36 +04:00
if ( rc = = USBAT_FLASH_MEDIA_NONE ) {
info - > sense_key = 0x02 ;
info - > sense_asc = 0x3A ;
info - > sense_ascq = 0x00 ;
return USB_STOR_TRANSPORT_FAILED ;
}
2005-09-30 15:49:36 +04:00
/* Check for media change */
2013-04-19 22:44:00 +04:00
rc = usbat_flash_check_media_changed ( us , uio ) ;
2005-04-17 02:20:36 +04:00
if ( rc = = USBAT_FLASH_MEDIA_CHANGED ) {
2005-09-30 15:49:36 +04:00
/* Reset and re-enable card detect */
2005-04-17 02:20:36 +04:00
rc = usbat_device_reset ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
rc = usbat_device_enable_cdt ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
msleep ( 50 ) ;
rc = usbat_read_user_io ( us , uio ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
info - > sense_key = UNIT_ATTENTION ;
info - > sense_asc = 0x28 ;
info - > sense_ascq = 0x00 ;
return USB_STOR_TRANSPORT_FAILED ;
}
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Determine whether we are controlling a flash - based reader / writer ,
* or a HP8200 - based CD drive .
* Sets transport functions as appropriate .
*/
static int usbat_identify_device ( struct us_data * us ,
struct usbat_info * info )
{
int rc ;
unsigned char status ;
if ( ! us | | ! info )
return USB_STOR_TRANSPORT_ERROR ;
rc = usbat_device_reset ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2005-11-17 20:48:01 +03:00
msleep ( 500 ) ;
2005-04-17 02:20:36 +04:00
/*
2005-08-10 21:30:04 +04:00
* In attempt to distinguish between HP CDRW ' s and Flash readers , we now
* execute the IDENTIFY PACKET DEVICE command . On ATA devices ( i . e . flash
* readers ) , this command should fail with error . On ATAPI devices ( i . e .
* CDROM drives ) , it should succeed .
2005-04-17 02:20:36 +04:00
*/
2005-08-10 21:30:04 +04:00
rc = usbat_write ( us , USBAT_ATA , USBAT_ATA_CMD , 0xA1 ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-04-17 02:20:36 +04:00
2005-08-10 21:30:04 +04:00
rc = usbat_get_status ( us , & status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Check for error bit, or if the command 'fell through' */
2005-09-29 03:14:21 +04:00
if ( status = = 0xA1 | | ! ( status & 0x01 ) ) {
2005-09-30 15:49:36 +04:00
/* Device is HP 8200 */
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Detected HP8200 CDRW \n " ) ;
2005-04-17 02:20:36 +04:00
info - > devicetype = USBAT_DEV_HP8200 ;
2005-09-29 03:14:21 +04:00
} else {
2005-09-30 15:49:36 +04:00
/* Device is a CompactFlash reader/writer */
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Detected Flash reader/writer \n " ) ;
2005-09-29 03:14:21 +04:00
info - > devicetype = USBAT_DEV_FLASH ;
2005-04-17 02:20:36 +04:00
}
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Set the transport function based on the device type
*/
static int usbat_set_transport ( struct us_data * us ,
2006-05-02 21:29:34 +04:00
struct usbat_info * info ,
int devicetype )
2005-04-17 02:20:36 +04:00
{
2006-05-02 21:29:34 +04:00
if ( ! info - > devicetype )
info - > devicetype = devicetype ;
2005-04-17 02:20:36 +04:00
2006-05-02 21:29:34 +04:00
if ( ! info - > devicetype )
usbat_identify_device ( us , info ) ;
switch ( info - > devicetype ) {
default :
return USB_STOR_TRANSPORT_ERROR ;
case USBAT_DEV_HP8200 :
2005-04-17 02:20:36 +04:00
us - > transport = usbat_hp8200e_transport ;
2006-05-02 21:29:34 +04:00
break ;
case USBAT_DEV_FLASH :
2005-04-17 02:20:36 +04:00
us - > transport = usbat_flash_transport ;
2006-05-02 21:29:34 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Read the media capacity
*/
static int usbat_flash_get_sector_count ( struct us_data * us ,
struct usbat_info * info )
{
unsigned char registers [ 3 ] = {
USBAT_ATA_SECCNT ,
USBAT_ATA_DEVICE ,
USBAT_ATA_CMD ,
} ;
unsigned char command [ 3 ] = { 0x01 , 0xA0 , 0xEC } ;
unsigned char * reply ;
unsigned char status ;
int rc ;
if ( ! us | | ! info )
return USB_STOR_TRANSPORT_ERROR ;
reply = kmalloc ( 512 , GFP_NOIO ) ;
if ( ! reply )
return USB_STOR_TRANSPORT_ERROR ;
2005-09-30 15:49:36 +04:00
/* ATA command : IDENTIFY DEVICE */
2005-04-17 02:20:36 +04:00
rc = usbat_multiple_write ( us , registers , command , 3 ) ;
if ( rc ! = USB_STOR_XFER_GOOD ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Gah! identify_device failed \n " ) ;
2005-04-17 02:20:36 +04:00
rc = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
2005-09-30 15:49:36 +04:00
/* Read device status */
2005-04-17 02:20:36 +04:00
if ( usbat_get_status ( us , & status ) ! = USB_STOR_XFER_GOOD ) {
rc = USB_STOR_TRANSPORT_ERROR ;
goto leave ;
}
msleep ( 100 ) ;
2005-09-30 15:49:36 +04:00
/* Read the device identification data */
2006-05-02 21:30:12 +04:00
rc = usbat_read_block ( us , reply , 512 , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
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 ;
}
/*
* Read data from device
*/
static int usbat_flash_read_data ( struct us_data * us ,
struct usbat_info * info ,
u32 sector ,
u32 sectors )
{
unsigned char registers [ 7 ] = {
USBAT_ATA_FEATURES ,
USBAT_ATA_SECCNT ,
USBAT_ATA_SECNUM ,
USBAT_ATA_LBA_ME ,
USBAT_ATA_LBA_HI ,
USBAT_ATA_DEVICE ,
USBAT_ATA_STATUS ,
} ;
unsigned char command [ 7 ] ;
unsigned char * buffer ;
unsigned char thistime ;
unsigned int totallen , alloclen ;
int len , result ;
2007-05-11 14:33:09 +04:00
unsigned int sg_offset = 0 ;
struct scatterlist * sg = NULL ;
2005-04-17 02:20:36 +04:00
result = usbat_flash_check_media ( us , info ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
return result ;
2005-09-30 15:49:36 +04:00
/*
* 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 > 8 GB CF card .
*/
2005-04-17 02:20:36 +04:00
if ( sector > 0x0FFFFFFF )
return USB_STOR_TRANSPORT_ERROR ;
totallen = sectors * info - > ssize ;
2005-09-30 15:49:36 +04:00
/*
* 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 .
*/
2005-04-17 02:20:36 +04:00
alloclen = min ( totallen , 65536u ) ;
buffer = kmalloc ( alloclen , GFP_NOIO ) ;
if ( buffer = = NULL )
return USB_STOR_TRANSPORT_ERROR ;
do {
2005-09-30 15:49:36 +04:00
/*
* loop , never allocate or transfer more than 64 k at once
* ( min ( 128 k , 255 * info - > ssize ) is the real limit )
*/
2005-04-17 02:20:36 +04:00
len = min ( totallen , alloclen ) ;
thistime = ( len / info - > ssize ) & 0xff ;
2005-09-30 15:49:36 +04:00
/* ATA command 0x20 (READ SECTORS) */
usbat_pack_ata_sector_cmd ( command , thistime , sector , 0x20 ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Write/execute ATA read command */
2005-04-17 02:20:36 +04:00
result = usbat_multiple_write ( us , registers , command , 7 ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
goto leave ;
2005-09-30 15:49:36 +04:00
/* Read the data we just requested */
2006-05-02 21:30:12 +04:00
result = usbat_read_blocks ( us , buffer , len , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_TRANSPORT_GOOD )
goto leave ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " %d bytes \n " , len ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Store the data in the transfer buffer */
2005-04-17 02:20:36 +04:00
usb_stor_access_xfer_buf ( buffer , len , us - > srb ,
2007-05-11 14:33:09 +04:00
& sg , & sg_offset , TO_XFER_BUF ) ;
2005-04-17 02:20:36 +04:00
sector + = thistime ;
totallen - = len ;
} while ( totallen > 0 ) ;
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_GOOD ;
leave :
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
/*
* Write data to device
*/
static int usbat_flash_write_data ( struct us_data * us ,
struct usbat_info * info ,
u32 sector ,
u32 sectors )
{
unsigned char registers [ 7 ] = {
USBAT_ATA_FEATURES ,
USBAT_ATA_SECCNT ,
USBAT_ATA_SECNUM ,
USBAT_ATA_LBA_ME ,
USBAT_ATA_LBA_HI ,
USBAT_ATA_DEVICE ,
USBAT_ATA_STATUS ,
} ;
unsigned char command [ 7 ] ;
unsigned char * buffer ;
unsigned char thistime ;
unsigned int totallen , alloclen ;
int len , result ;
2007-05-11 14:33:09 +04:00
unsigned int sg_offset = 0 ;
struct scatterlist * sg = NULL ;
2005-04-17 02:20:36 +04:00
result = usbat_flash_check_media ( us , info ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
return result ;
2005-09-30 15:49:36 +04:00
/*
* we ' re working in LBA mode . according to the ATA spec ,
* we can support up to 28 - bit addressing . I don ' t know if the device
* supports beyond 24 - bit addressing . It ' s kind of hard to test
* since it requires > 8 GB media .
*/
2005-04-17 02:20:36 +04:00
if ( sector > 0x0FFFFFFF )
return USB_STOR_TRANSPORT_ERROR ;
totallen = sectors * info - > ssize ;
2005-09-30 15:49:36 +04:00
/*
* 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 .
*/
2005-04-17 02:20:36 +04:00
alloclen = min ( totallen , 65536u ) ;
buffer = kmalloc ( alloclen , GFP_NOIO ) ;
if ( buffer = = NULL )
return USB_STOR_TRANSPORT_ERROR ;
do {
2005-09-30 15:49:36 +04:00
/*
* loop , never allocate or transfer more than 64 k at once
* ( min ( 128 k , 255 * info - > ssize ) is the real limit )
*/
2005-04-17 02:20:36 +04:00
len = min ( totallen , alloclen ) ;
thistime = ( len / info - > ssize ) & 0xff ;
2005-09-30 15:49:36 +04:00
/* Get the data from the transfer buffer */
2005-04-17 02:20:36 +04:00
usb_stor_access_xfer_buf ( buffer , len , us - > srb ,
2007-05-11 14:33:09 +04:00
& sg , & sg_offset , FROM_XFER_BUF ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* ATA command 0x30 (WRITE SECTORS) */
usbat_pack_ata_sector_cmd ( command , thistime , sector , 0x30 ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Write/execute ATA write command */
2005-04-17 02:20:36 +04:00
result = usbat_multiple_write ( us , registers , command , 7 ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
goto leave ;
2005-09-30 15:49:36 +04:00
/* Write the data */
2006-05-02 21:30:12 +04:00
result = usbat_write_blocks ( us , buffer , len , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_TRANSPORT_GOOD )
goto leave ;
sector + = thistime ;
totallen - = len ;
} while ( totallen > 0 ) ;
kfree ( buffer ) ;
return result ;
leave :
kfree ( buffer ) ;
return USB_STOR_TRANSPORT_ERROR ;
}
/*
* Squeeze a potentially huge ( > 65535 byte ) read10 command into
* a little ( < = 65535 byte ) ATAPI pipe
*/
static int usbat_hp8200e_handle_read10 ( struct us_data * us ,
unsigned char * registers ,
unsigned char * data ,
struct scsi_cmnd * srb )
{
int result = USB_STOR_TRANSPORT_GOOD ;
unsigned char * buffer ;
unsigned int len ;
unsigned int sector ;
unsigned int sg_offset = 0 ;
2007-05-11 14:33:09 +04:00
struct scatterlist * sg = NULL ;
2005-04-17 02:20:36 +04:00
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " transfersize %d \n " , srb - > transfersize ) ;
2005-04-17 02:20:36 +04:00
2007-09-09 21:40:56 +04:00
if ( scsi_bufflen ( srb ) < 0x10000 ) {
2005-04-17 02:20:36 +04:00
result = usbat_hp8200e_rw_block_test ( us , USBAT_ATA ,
registers , data , 19 ,
USBAT_ATA_DATA , USBAT_ATA_STATUS , 0xFD ,
( USBAT_QUAL_FCQ | USBAT_QUAL_ALQ ) ,
DMA_FROM_DEVICE ,
2007-09-09 21:40:56 +04:00
scsi_sglist ( srb ) ,
scsi_bufflen ( srb ) , scsi_sg_count ( srb ) , 1 ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/*
* Since we ' re requesting more data than we can handle in
* a single read command ( max is 64 k - 1 ) , we will perform
* multiple reads , but each read must be in multiples of
* a sector . Luckily the sector size is in srb - > transfersize
* ( see linux / drivers / scsi / sr . c ) .
*/
if ( data [ 7 + 0 ] = = GPCMD_READ_CD ) {
len = short_pack ( data [ 7 + 9 ] , data [ 7 + 8 ] ) ;
len < < = 16 ;
len | = data [ 7 + 7 ] ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " GPCMD_READ_CD: len %d \n " , len ) ;
2007-09-09 21:40:56 +04:00
srb - > transfersize = scsi_bufflen ( srb ) / len ;
2005-04-17 02:20:36 +04:00
}
if ( ! srb - > transfersize ) {
srb - > transfersize = 2048 ; /* A guess */
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " transfersize 0, forcing %d \n " ,
srb - > transfersize ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 15:49:36 +04:00
/*
* 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 .
*/
2005-04-17 02:20:36 +04:00
len = ( 65535 / srb - > transfersize ) * srb - > transfersize ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Max read is %d bytes \n " , len ) ;
2007-09-09 21:40:56 +04:00
len = min ( len , scsi_bufflen ( srb ) ) ;
2005-04-17 02:20:36 +04:00
buffer = kmalloc ( len , GFP_NOIO ) ;
2005-09-30 15:49:36 +04:00
if ( buffer = = NULL ) /* bloody hell! */
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_FAILED ;
sector = short_pack ( data [ 7 + 3 ] , data [ 7 + 2 ] ) ;
sector < < = 16 ;
sector | = short_pack ( data [ 7 + 5 ] , data [ 7 + 4 ] ) ;
transferred = 0 ;
2007-09-09 21:40:56 +04:00
while ( transferred ! = scsi_bufflen ( srb ) ) {
2005-04-17 02:20:36 +04:00
2007-09-09 21:40:56 +04:00
if ( len > scsi_bufflen ( srb ) - transferred )
len = scsi_bufflen ( srb ) - transferred ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
data [ 3 ] = len & 0xFF ; /* (cylL) = expected length (L) */
data [ 4 ] = ( len > > 8 ) & 0xFF ; /* (cylH) = expected length (H) */
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Fix up the SCSI command sector and num sectors */
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
data [ 7 + 2 ] = MSB_of ( sector > > 16 ) ; /* SCSI command sector */
2005-04-17 02:20:36 +04:00
data [ 7 + 3 ] = LSB_of ( sector > > 16 ) ;
data [ 7 + 4 ] = MSB_of ( sector & 0xFFFF ) ;
data [ 7 + 5 ] = LSB_of ( sector & 0xFFFF ) ;
if ( data [ 7 + 0 ] = = GPCMD_READ_CD )
data [ 7 + 6 ] = 0 ;
2005-09-30 15:49:36 +04:00
data [ 7 + 7 ] = MSB_of ( len / srb - > transfersize ) ; /* SCSI command */
data [ 7 + 8 ] = LSB_of ( len / srb - > transfersize ) ; /* num sectors */
2005-04-17 02:20:36 +04:00
result = usbat_hp8200e_rw_block_test ( us , USBAT_ATA ,
registers , data , 19 ,
USBAT_ATA_DATA , USBAT_ATA_STATUS , 0xFD ,
( USBAT_QUAL_FCQ | USBAT_QUAL_ALQ ) ,
DMA_FROM_DEVICE ,
buffer ,
len , 0 , 1 ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
break ;
2005-09-30 15:49:36 +04:00
/* Store the data in the transfer buffer */
2005-04-17 02:20:36 +04:00
usb_stor_access_xfer_buf ( buffer , len , srb ,
2007-05-11 14:33:09 +04:00
& sg , & sg_offset , TO_XFER_BUF ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Update the amount transferred and the sector number */
2005-04-17 02:20:36 +04:00
transferred + = len ;
sector + = len / srb - > transfersize ;
2007-09-09 21:40:56 +04:00
} /* while transferred != scsi_bufflen(srb) */
2005-04-17 02:20:36 +04:00
kfree ( buffer ) ;
return result ;
}
static int usbat_select_and_test_registers ( struct us_data * us )
{
int selector ;
unsigned char * status = us - > iobuf ;
2005-09-30 15:49:36 +04:00
/* try device = master, then device = slave. */
2005-08-10 21:30:04 +04:00
for ( selector = 0xA0 ; selector < = 0xB0 ; selector + = 0x10 ) {
if ( usbat_write ( us , USBAT_ATA , USBAT_ATA_DEVICE , selector ) ! =
2005-04-17 02:20:36 +04:00
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_STATUS , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_DEVICE , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_ME , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_HI , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_write ( us , USBAT_ATA , USBAT_ATA_LBA_ME , 0x55 ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_write ( us , USBAT_ATA , USBAT_ATA_LBA_HI , 0xAA ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_ME , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_ME , status ) ! =
USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
}
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Initialize the USBAT processor and the storage device
*/
2006-05-02 21:29:34 +04:00
static int init_usbat ( struct us_data * us , int devicetype )
2005-04-17 02:20:36 +04:00
{
int rc ;
struct usbat_info * info ;
unsigned char subcountH = USBAT_ATA_LBA_HI ;
unsigned char subcountL = USBAT_ATA_LBA_ME ;
unsigned char * status = us - > iobuf ;
2006-01-08 14:33:45 +03:00
us - > extra = kzalloc ( sizeof ( struct usbat_info ) , GFP_NOIO ) ;
2013-04-19 22:44:00 +04:00
if ( ! us - > extra )
2005-04-17 02:20:36 +04:00
return 1 ;
2013-04-19 22:44:00 +04:00
2005-04-17 02:20:36 +04:00
info = ( struct usbat_info * ) ( us - > extra ) ;
2005-09-30 15:49:36 +04:00
/* Enable peripheral control signals */
2005-04-17 02:20:36 +04:00
rc = usbat_write_user_io ( us ,
USBAT_UIO_OE1 | USBAT_UIO_OE0 ,
USBAT_UIO_EPAD | USBAT_UIO_1 ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 1 \n " ) ;
2005-04-17 02:20:36 +04:00
msleep ( 2000 ) ;
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 2 \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 3 \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_select_and_test_registers ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 4 \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 5 \n " ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/* Enable peripheral control signals and card detect */
2005-04-17 02:20:36 +04:00
rc = usbat_device_enable_cdt ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 6 \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 7 \n " ) ;
2005-04-17 02:20:36 +04:00
msleep ( 1400 ) ;
rc = usbat_read_user_io ( us , status ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 8 \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_select_and_test_registers ( us ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 9 \n " ) ;
2005-08-10 21:30:04 +04:00
2005-09-30 15:49:36 +04:00
/* At this point, we need to detect which device we are using */
2006-05-02 21:29:34 +04:00
if ( usbat_set_transport ( us , info , devicetype ) )
2005-08-10 21:30:04 +04:00
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 10 \n " ) ;
2005-04-17 02:20:36 +04:00
if ( usbat_get_device_type ( us ) = = USBAT_DEV_FLASH ) {
subcountH = 0x02 ;
subcountL = 0x00 ;
}
rc = usbat_set_shuttle_features ( us , ( USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1 ) ,
0x00 , 0x88 , 0x08 , subcountH , subcountL ) ;
if ( rc ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INIT 11 \n " ) ;
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_GOOD ;
}
/*
* Transport for the HP 8200 e
*/
static int usbat_hp8200e_transport ( struct scsi_cmnd * srb , struct us_data * us )
{
int result ;
unsigned char * status = us - > iobuf ;
unsigned char registers [ 32 ] ;
unsigned char data [ 32 ] ;
unsigned int len ;
int i ;
2007-09-09 21:40:56 +04:00
len = scsi_bufflen ( srb ) ;
2005-04-17 02:20:36 +04:00
/* Send A0 (ATA PACKET COMMAND).
Note : I guess we ' re never going to get any of the ATA
commands . . . just ATA Packet Commands .
*/
registers [ 0 ] = USBAT_ATA_FEATURES ;
registers [ 1 ] = USBAT_ATA_SECCNT ;
registers [ 2 ] = USBAT_ATA_SECNUM ;
registers [ 3 ] = USBAT_ATA_LBA_ME ;
registers [ 4 ] = USBAT_ATA_LBA_HI ;
registers [ 5 ] = USBAT_ATA_DEVICE ;
registers [ 6 ] = USBAT_ATA_CMD ;
data [ 0 ] = 0x00 ;
data [ 1 ] = 0x00 ;
data [ 2 ] = 0x00 ;
2005-09-30 15:49:36 +04:00
data [ 3 ] = len & 0xFF ; /* (cylL) = expected length (L) */
data [ 4 ] = ( len > > 8 ) & 0xFF ; /* (cylH) = expected length (H) */
data [ 5 ] = 0xB0 ; /* (device sel) = slave */
data [ 6 ] = 0xA0 ; /* (command) = ATA PACKET COMMAND */
2005-04-17 02:20:36 +04:00
for ( i = 7 ; i < 19 ; i + + ) {
registers [ i ] = 0x10 ;
data [ i ] = ( i - 7 > = srb - > cmd_len ) ? 0 : srb - > cmnd [ i - 7 ] ;
}
result = usbat_get_status ( us , status ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Status = %02X \n " , * status ) ;
2005-04-17 02:20:36 +04:00
if ( result ! = USB_STOR_XFER_GOOD )
return USB_STOR_TRANSPORT_ERROR ;
if ( srb - > cmnd [ 0 ] = = TEST_UNIT_READY )
transferred = 0 ;
if ( srb - > sc_data_direction = = DMA_TO_DEVICE ) {
result = usbat_hp8200e_rw_block_test ( us , USBAT_ATA ,
registers , data , 19 ,
USBAT_ATA_DATA , USBAT_ATA_STATUS , 0xFD ,
( USBAT_QUAL_FCQ | USBAT_QUAL_ALQ ) ,
DMA_TO_DEVICE ,
2007-09-09 21:40:56 +04:00
scsi_sglist ( srb ) ,
len , scsi_sg_count ( srb ) , 10 ) ;
2005-04-17 02:20:36 +04:00
if ( result = = USB_STOR_TRANSPORT_GOOD ) {
transferred + = len ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Wrote %08X bytes \n " , transferred ) ;
2005-04-17 02:20:36 +04:00
}
return result ;
} else if ( srb - > cmnd [ 0 ] = = READ_10 | |
srb - > cmnd [ 0 ] = = GPCMD_READ_CD ) {
return usbat_hp8200e_handle_read10 ( us , registers , data , srb ) ;
}
if ( len > 0xFFFF ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Error: len = %08X... what do I do now? \n " ,
len ) ;
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_ERROR ;
}
2010-02-17 13:50:26 +03:00
result = usbat_multiple_write ( us , registers , data , 7 ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
2005-04-17 02:20:36 +04:00
return result ;
2005-09-30 15:49:36 +04:00
/*
* Write the 12 - byte command header .
*
* If the command is BLANK then set the timer for 75 minutes .
* Otherwise set it for 10 minutes .
*
* NOTE : THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
* AT SPEED 4 IS UNRELIABLE ! ! !
*/
2005-04-17 02:20:36 +04:00
2010-02-17 13:50:26 +03:00
result = usbat_write_block ( us , USBAT_ATA , srb - > cmnd , 12 ,
srb - > cmnd [ 0 ] = = GPCMD_BLANK ? 75 : 10 , 0 ) ;
if ( result ! = USB_STOR_TRANSPORT_GOOD )
2005-04-17 02:20:36 +04:00
return result ;
2005-09-30 15:49:36 +04:00
/* If there is response data to be read in then do it here. */
2005-04-17 02:20:36 +04:00
if ( len ! = 0 & & ( srb - > sc_data_direction = = DMA_FROM_DEVICE ) ) {
2005-09-30 15:49:36 +04:00
/* How many bytes to read in? Check cylL register */
2005-04-17 02:20:36 +04:00
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_ME , status ) ! =
USB_STOR_XFER_GOOD ) {
return USB_STOR_TRANSPORT_ERROR ;
}
2005-09-30 15:49:36 +04:00
if ( len > 0xFF ) { /* need to read cylH also */
2005-04-17 02:20:36 +04:00
len = * status ;
if ( usbat_read ( us , USBAT_ATA , USBAT_ATA_LBA_HI , status ) ! =
USB_STOR_XFER_GOOD ) {
return USB_STOR_TRANSPORT_ERROR ;
}
len + = ( ( unsigned int ) * status ) < < 8 ;
}
else
len = * status ;
2007-09-09 21:40:56 +04:00
result = usbat_read_block ( us , scsi_sglist ( srb ) , len ,
scsi_sg_count ( srb ) ) ;
2005-04-17 02:20:36 +04:00
}
return result ;
}
/*
* Transport for USBAT02 - based CompactFlash and similar storage devices
*/
static int usbat_flash_transport ( struct scsi_cmnd * srb , struct us_data * us )
{
int rc ;
struct usbat_info * info = ( struct usbat_info * ) ( us - > extra ) ;
unsigned long block , blocks ;
unsigned char * ptr = us - > iobuf ;
static unsigned char inquiry_response [ 36 ] = {
0x00 , 0x80 , 0x00 , 0x01 , 0x1F , 0x00 , 0x00 , 0x00
} ;
if ( srb - > cmnd [ 0 ] = = INQUIRY ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " INQUIRY - Returning bogus response \n " ) ;
2005-04-17 02:20:36 +04:00
memcpy ( ptr , inquiry_response , sizeof ( inquiry_response ) ) ;
fill_inquiry_response ( us , ptr , 36 ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
if ( srb - > cmnd [ 0 ] = = READ_CAPACITY ) {
rc = usbat_flash_check_media ( us , info ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
rc = usbat_flash_get_sector_count ( us , info ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
2005-09-30 15:49:36 +04:00
/* hard coded 512 byte sectors as per ATA spec */
info - > ssize = 0x200 ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " READ_CAPACITY: %ld sectors, %ld bytes per sector \n " ,
info - > sectors , info - > ssize ) ;
2005-04-17 02:20:36 +04:00
2005-09-30 15:49:36 +04:00
/*
* build the reply
* note : must return the sector number of the last sector ,
* * not * the total number of sectors
*/
2005-04-17 02:20:36 +04:00
( ( __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 ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Gah! MODE_SELECT_10 \n " ) ;
2005-04-17 02:20:36 +04:00
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 ] ) ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " READ_10: read block 0x%04lx count %ld \n " ,
block , blocks ) ;
2005-04-17 02:20:36 +04:00
return usbat_flash_read_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = READ_12 ) {
2005-09-30 15:49:36 +04:00
/*
* I don ' t think we ' ll ever see a READ_12 but support it anyway
*/
2005-04-17 02:20:36 +04:00
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 ] ) ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " READ_12: read block 0x%04lx count %ld \n " ,
block , blocks ) ;
2005-04-17 02:20:36 +04:00
return usbat_flash_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 ] ) ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " WRITE_10: write block 0x%04lx count %ld \n " ,
block , blocks ) ;
2005-04-17 02:20:36 +04:00
return usbat_flash_write_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = WRITE_12 ) {
2005-09-30 15:49:36 +04:00
/*
* I don ' t think we ' ll ever see a WRITE_12 but support it anyway
*/
2005-04-17 02:20:36 +04:00
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 ] ) ) ;
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " WRITE_12: write block 0x%04lx count %ld \n " ,
block , blocks ) ;
2005-04-17 02:20:36 +04:00
return usbat_flash_write_data ( us , info , block , blocks ) ;
}
if ( srb - > cmnd [ 0 ] = = TEST_UNIT_READY ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " TEST_UNIT_READY \n " ) ;
2005-04-17 02:20:36 +04:00
rc = usbat_flash_check_media ( us , info ) ;
if ( rc ! = USB_STOR_TRANSPORT_GOOD )
return rc ;
return usbat_check_status ( us ) ;
}
if ( srb - > cmnd [ 0 ] = = REQUEST_SENSE ) {
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " REQUEST_SENSE \n " ) ;
2005-04-17 02:20:36 +04:00
memset ( ptr , 0 , 18 ) ;
ptr [ 0 ] = 0xF0 ;
ptr [ 2 ] = info - > sense_key ;
ptr [ 7 ] = 11 ;
ptr [ 12 ] = info - > sense_asc ;
ptr [ 13 ] = info - > sense_ascq ;
usb_stor_set_xfer_buf ( ptr , 18 , srb ) ;
return USB_STOR_TRANSPORT_GOOD ;
}
if ( srb - > cmnd [ 0 ] = = ALLOW_MEDIUM_REMOVAL ) {
2005-09-30 15:49:36 +04:00
/*
* sure . whatever . not like we can stop the user from popping
* the media out of the device ( no locking doors , etc )
*/
2005-04-17 02:20:36 +04:00
return USB_STOR_TRANSPORT_GOOD ;
}
2013-04-19 22:44:00 +04:00
usb_stor_dbg ( us , " Gah! Unknown command: %d (0x%x) \n " ,
srb - > cmnd [ 0 ] , srb - > cmnd [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
info - > sense_key = 0x05 ;
info - > sense_asc = 0x20 ;
info - > sense_ascq = 0x00 ;
return USB_STOR_TRANSPORT_FAILED ;
}
2009-02-12 22:48:08 +03:00
static int init_usbat_cd ( struct us_data * us )
2006-05-02 21:29:34 +04:00
{
return init_usbat ( us , USBAT_DEV_HP8200 ) ;
}
2009-02-12 22:48:08 +03:00
static int init_usbat_flash ( struct us_data * us )
2006-05-02 21:29:34 +04:00
{
return init_usbat ( us , USBAT_DEV_FLASH ) ;
}
2009-02-12 22:48:08 +03:00
static int usbat_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
2006-05-02 21:29:34 +04:00
{
2009-02-12 22:48:08 +03:00
struct us_data * us ;
int result ;
result = usb_stor_probe1 ( & us , intf , id ,
( id - usbat_usb_ids ) + usbat_unusual_dev_list ) ;
if ( result )
return result ;
/* The actual transport will be determined later by the
* initialization routine ; this is just a placeholder .
*/
us - > transport_name = " Shuttle USBAT " ;
us - > transport = usbat_flash_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 1 ;
result = usb_stor_probe2 ( us ) ;
return result ;
2006-05-02 21:29:34 +04:00
}
2009-02-12 22:48:08 +03:00
static struct usb_driver usbat_driver = {
. name = " ums-usbat " ,
. probe = usbat_probe ,
. disconnect = usb_stor_disconnect ,
. suspend = usb_stor_suspend ,
. resume = usb_stor_resume ,
. reset_resume = usb_stor_reset_resume ,
. pre_reset = usb_stor_pre_reset ,
. post_reset = usb_stor_post_reset ,
. id_table = usbat_usb_ids ,
. soft_unbind = 1 ,
2012-01-14 06:15:21 +04:00
. no_dynamic_id = 1 ,
2009-02-12 22:48:08 +03:00
} ;
2011-11-18 21:34:02 +04:00
module_usb_driver ( usbat_driver ) ;