2005-04-17 02:20:36 +04:00
/* Driver for SanDisk SDDR-55 SmartMedia reader
*
* 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 0213 9 , USA .
*/
# include <linux/jiffies.h>
# include <linux/errno.h>
2009-02-12 22:47:59 +03:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# 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"
2009-02-12 22:47:59 +03:00
2009-02-28 23:39:20 +03:00
MODULE_DESCRIPTION ( " Driver for SanDisk SDDR-55 SmartMedia reader " ) ;
MODULE_AUTHOR ( " Simon Munton " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-02-12 22:47:59 +03:00
/*
* The table of devices
*/
# define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName , productName , useProtocol , useTransport , \
initFunction , flags ) \
{ USB_DEVICE_VER ( id_vendor , id_product , bcdDeviceMin , bcdDeviceMax ) , \
. driver_info = ( flags ) | ( USB_US_TYPE_STOR < < 24 ) }
struct usb_device_id sddr55_usb_ids [ ] = {
# include "unusual_sddr55.h"
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , sddr55_usb_ids ) ;
# undef UNUSUAL_DEV
/*
* The flags table
*/
# define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name , product_name , use_protocol , use_transport , \
init_function , Flags ) \
{ \
. vendorName = vendor_name , \
. productName = product_name , \
. useProtocol = use_protocol , \
. useTransport = use_transport , \
. initFunction = init_function , \
}
static struct us_unusual_dev sddr55_unusual_dev_list [ ] = {
# include "unusual_sddr55.h"
{ } /* Terminating entry */
} ;
# undef UNUSUAL_DEV
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)
# 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 */
2005-04-19 04:39:34 +04:00
kfree ( info - > lba_to_pba ) ;
kfree ( info - > pba_to_lba ) ;
2005-04-17 02:20:36 +04:00
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 ;
2007-05-11 14:33:09 +04:00
unsigned int len , offset ;
struct scatterlist * sg ;
2005-04-17 02:20: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.
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 */
2007-05-11 14:33:09 +04:00
offset = 0 ;
sg = NULL ;
2005-04-17 02:20:36 +04:00
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 ,
2007-05-11 14:33:09 +04:00
& sg , & offset , TO_XFER_BUF ) ;
2005-04-17 02:20:36 +04:00
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 ;
2007-05-11 14:33:09 +04:00
unsigned int len , offset ;
struct scatterlist * sg ;
2005-04-17 02:20:36 +04:00
/* 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 ;
2007-05-11 14:33:09 +04:00
offset = 0 ;
sg = NULL ;
2005-04-17 02:20:36 +04:00
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 ,
2007-05-11 14:33:09 +04:00
& sg , & offset , FROM_XFER_BUF ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2009-02-12 22:47:59 +03:00
static int sddr55_reset ( struct us_data * us )
{
2005-04-17 02:20:36 +04:00
return 0 ;
}
static unsigned long sddr55_get_capacity ( struct us_data * us ) {
2008-03-05 02:25:08 +03:00
unsigned char uninitialized_var ( manufacturerID ) ;
unsigned char uninitialized_var ( deviceID ) ;
2005-04-17 02:20:36 +04:00
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 ;
}
2005-04-19 04:39:34 +04:00
kfree ( info - > lba_to_pba ) ;
kfree ( info - > pba_to_lba ) ;
2005-04-17 02:20:36 +04:00
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 ) {
2005-04-19 04:39:34 +04:00
kfree ( info - > lba_to_pba ) ;
kfree ( info - > pba_to_lba ) ;
2005-04-17 02:20:36 +04:00
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 8 MB 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 ) {
2009-02-05 18:16:24 +03:00
printk ( KERN_WARNING
" sddr55: map inconsistency at LBA %04X \n " ,
lba + zone * 1000 ) ;
2005-04-17 02:20:36 +04:00
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 ;
2005-04-19 04:39:34 +04:00
kfree ( info - > lba_to_pba ) ;
kfree ( info - > pba_to_lba ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Transport for the Sandisk SDDR - 55
*/
2009-02-12 22:47:59 +03:00
static int sddr55_transport ( struct scsi_cmnd * srb , struct us_data * us )
2005-04-17 02:20:36 +04:00
{
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 ) {
2006-01-08 14:33:45 +03:00
us - > extra = kzalloc (
2005-04-17 02:20:36 +04:00
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?
}
2009-02-12 22:47:59 +03:00
static int sddr55_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct us_data * us ;
int result ;
result = usb_stor_probe1 ( & us , intf , id ,
( id - sddr55_usb_ids ) + sddr55_unusual_dev_list ) ;
if ( result )
return result ;
us - > transport_name = " SDDR55 " ;
us - > transport = sddr55_transport ;
us - > transport_reset = sddr55_reset ;
us - > max_lun = 0 ;
result = usb_stor_probe2 ( us ) ;
return result ;
}
static struct usb_driver sddr55_driver = {
. name = " ums-sddr55 " ,
. probe = sddr55_probe ,
. disconnect = usb_stor_disconnect ,
. suspend = usb_stor_suspend ,
. resume = usb_stor_resume ,
. reset_resume = usb_stor_reset_resume ,
. pre_reset = usb_stor_pre_reset ,
. post_reset = usb_stor_post_reset ,
. id_table = sddr55_usb_ids ,
. soft_unbind = 1 ,
} ;
static int __init sddr55_init ( void )
{
return usb_register ( & sddr55_driver ) ;
}
static void __exit sddr55_exit ( void )
{
usb_deregister ( & sddr55_driver ) ;
}
module_init ( sddr55_init ) ;
module_exit ( sddr55_exit ) ;