mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-15 16:05:10 +01:00
e510233154
*Fixed reset of the loader when loading game with IOS reload and disabled WiiTDB titles (Issue 1874) *Added new 'Inherit' or 'Use global' setting for game settings. If that option is set than the global setting is used for that option. (Issue 1842) *Fixed timeout timer on startup to count correctly. (Issue 1907) *Added two new video modes to force progressive video mode, 'FORCE PAL480p' and 'FORCE NTSC480p' (basically the same but oh well) (Issue 1902) *Added the new 'Return to' procedure for the d2x v4 IOS for Test purpose (didn't test it, need feedback on this one). The old method is used if this procedure fails. Please test it on problematic games (e.g. PoP). (Issue 1892)
2169 lines
46 KiB
C
2169 lines
46 KiB
C
/*-------------------------------------------------------------
|
|
|
|
usbstorage.c -- Bulk-only USB mass storage support
|
|
|
|
Copyright (C) 2008
|
|
Sven Peter (svpe) <svpe@gmx.net>
|
|
|
|
quick port to ehci/ios: Kwiirk
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any
|
|
damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
purpose, including commercial applications, and to alter it and
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you
|
|
must not claim that you wrote the original software. If you use
|
|
this software in a product, an acknowledgment in the product
|
|
documentation would be appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
must not be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
|
|
-------------------------------------------------------------*/
|
|
|
|
#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
|
|
|
|
//#define HEAP_SIZE (32*1024)
|
|
//#define TAG_START 0x22112211
|
|
|
|
#define TAG_START 0x2C0DE001
|
|
|
|
#define CBW_SIZE 31
|
|
#define CBW_SIGNATURE 0x43425355
|
|
#define CBW_IN (1 << 7)
|
|
#define CBW_OUT 0
|
|
|
|
|
|
#define CSW_SIZE 13
|
|
#define CSW_SIGNATURE 0x53425355
|
|
|
|
#define SCSI_TEST_UNIT_READY 0x00
|
|
#define SCSI_INQUIRY 0x12
|
|
#define SCSI_REQUEST_SENSE 0x03
|
|
#define SCSI_START_STOP 0x1b
|
|
#define SCSI_READ_CAPACITY 0x25
|
|
#define SCSI_READ_10 0x28
|
|
#define SCSI_WRITE_10 0x2A
|
|
|
|
#define SCSI_SENSE_REPLY_SIZE 18
|
|
#define SCSI_SENSE_NOT_READY 0x02
|
|
#define SCSI_SENSE_MEDIUM_ERROR 0x03
|
|
#define SCSI_SENSE_HARDWARE_ERROR 0x04
|
|
|
|
#define USB_CLASS_MASS_STORAGE 0x08
|
|
#define USB_CLASS_HUB 0x09
|
|
|
|
#define MASS_STORAGE_RBC_COMMANDS 0x01
|
|
#define MASS_STORAGE_ATA_COMMANDS 0x02
|
|
#define MASS_STORAGE_QIC_COMMANDS 0x03
|
|
#define MASS_STORAGE_UFI_COMMANDS 0x04
|
|
#define MASS_STORAGE_SFF8070_COMMANDS 0x05
|
|
#define MASS_STORAGE_SCSI_COMMANDS 0x06
|
|
|
|
#define MASS_STORAGE_BULK_ONLY 0x50
|
|
|
|
#define USBSTORAGE_GET_MAX_LUN 0xFE
|
|
#define USBSTORAGE_RESET 0xFF
|
|
|
|
#define USB_ENDPOINT_BULK 0x02
|
|
|
|
#define USBSTORAGE_CYCLE_RETRIES 10
|
|
|
|
|
|
#define MAX_TRANSFER_SIZE 0x1000
|
|
|
|
#define DEVLIST_MAXSIZE 8
|
|
|
|
|
|
extern char use_reset_bulk;
|
|
/* force_flags 1 ->force GetMaxLun, 2-> force SetConfiguration */
|
|
extern char force_flags;
|
|
extern char use_alternative_timeout;
|
|
|
|
int is_dvd=0;
|
|
|
|
int ums_init_done = 0;
|
|
|
|
static usbstorage_handle __usbfd;
|
|
static u8 __lun = 16;
|
|
static u8 __mounted = 0;
|
|
static u16 __vid = 0;
|
|
static u16 __pid = 0;
|
|
extern u32 current_port;
|
|
|
|
void reinit_ehci_headers(void);
|
|
void ehci_stop(void);
|
|
void ehci_run(void);
|
|
|
|
|
|
|
|
#define MEM_PRINT 1
|
|
|
|
#ifdef MEM_PRINT
|
|
|
|
char mem_cad[32];
|
|
|
|
|
|
#include <stdarg.h> // for the s_printf function
|
|
|
|
extern int verbose;
|
|
|
|
void int_char(int num)
|
|
{
|
|
int sign=num<0;
|
|
int n,m;
|
|
|
|
if(num==0)
|
|
{
|
|
mem_cad[0]='0';mem_cad[1]=0;
|
|
return;
|
|
}
|
|
|
|
for(n=0;n<10;n++)
|
|
{
|
|
m=num % 10;num/=10;if(m<0) m=-m;
|
|
mem_cad[25-n]=48+m;
|
|
}
|
|
|
|
mem_cad[26]=0;
|
|
|
|
n=0;m=16;
|
|
if(sign) {mem_cad[n]='-';n++;}
|
|
|
|
while(mem_cad[m]=='0') m++;
|
|
|
|
if(mem_cad[m]==0) m--;
|
|
|
|
while(mem_cad[m])
|
|
{
|
|
mem_cad[n]=mem_cad[m];
|
|
n++;m++;
|
|
}
|
|
mem_cad[n]=0;
|
|
|
|
}
|
|
|
|
void uint_char(unsigned int num)
|
|
{
|
|
int n,m;
|
|
|
|
if(num==0)
|
|
{
|
|
mem_cad[0]='0';mem_cad[1]=0;
|
|
return;
|
|
}
|
|
|
|
for(n=0;n<10;n++)
|
|
{
|
|
m=num % 10;num/=10;
|
|
mem_cad[25-n]=48+m;
|
|
}
|
|
|
|
mem_cad[26]=0;
|
|
|
|
n=0;m=16;
|
|
|
|
while(mem_cad[m]=='0') m++;
|
|
|
|
if(mem_cad[m]==0) m--;
|
|
|
|
while(mem_cad[m])
|
|
{
|
|
mem_cad[n]=mem_cad[m];
|
|
n++;m++;
|
|
}
|
|
mem_cad[n]=0;
|
|
|
|
}
|
|
|
|
void hex_char(u32 num)
|
|
{
|
|
int n,m;
|
|
|
|
if(num==0)
|
|
{
|
|
mem_cad[0]='0';mem_cad[1]=0;
|
|
return;
|
|
}
|
|
|
|
for(n=0;n<8;n++)
|
|
{
|
|
m=num & 15;num>>=4;
|
|
if(m>=10) m+=7;
|
|
mem_cad[23-n]=48+m;
|
|
}
|
|
|
|
mem_cad[24]=0;
|
|
|
|
n=0;m=16;
|
|
|
|
mem_cad[n]='0';n++;
|
|
mem_cad[n]='x';n++;
|
|
|
|
while(mem_cad[m]=='0') m++;
|
|
|
|
if(mem_cad[m]==0) m--;
|
|
|
|
while(mem_cad[m])
|
|
{
|
|
mem_cad[n]=mem_cad[m];
|
|
n++;m++;
|
|
}
|
|
mem_cad[n]=0;
|
|
|
|
}
|
|
|
|
|
|
void s_printf(char *format,...)
|
|
{
|
|
va_list opt;
|
|
|
|
char out[2]=" ";
|
|
|
|
int val;
|
|
|
|
char *s;
|
|
static int cnt=0;
|
|
va_start(opt, format);
|
|
|
|
while(format[0])
|
|
{
|
|
if(format[0]!='%') {out[0]=*format++;cnt+=strlen(out);if(cnt<3500)os_puts(out);}
|
|
else
|
|
{
|
|
format++;
|
|
switch(format[0])
|
|
{
|
|
case 'd':
|
|
case 'i':
|
|
val=va_arg(opt,int);
|
|
int_char(val);
|
|
|
|
cnt+=strlen(mem_cad);if(cnt<3500)os_puts(mem_cad);
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
val=va_arg(opt, unsigned);
|
|
uint_char(val);
|
|
|
|
cnt+=strlen(mem_cad);if(cnt<3500)os_puts(mem_cad);
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
val=va_arg(opt,int);
|
|
hex_char((u32) val);
|
|
cnt+=strlen(mem_cad);if(cnt<3500)os_puts(mem_cad);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
s=va_arg(opt,char *);
|
|
cnt+=strlen(s);if(cnt<3500)os_puts(s);
|
|
break;
|
|
|
|
}
|
|
format++;
|
|
}
|
|
|
|
}
|
|
|
|
va_end(opt);
|
|
|
|
|
|
}
|
|
|
|
void log_status(char *s)
|
|
{
|
|
return;
|
|
u32 status=ehci_readl( &ehci->regs->status);
|
|
u32 statusp=ehci_readl(&ehci->regs->port_status[current_port]);
|
|
|
|
s_printf(" log_status (%s)\n",s);
|
|
|
|
s_printf(" status: %x %s%s%s%s%s%s%s%s%s%s\n",
|
|
status,
|
|
(status & STS_ASS) ? " Async" : "",
|
|
(status & STS_PSS) ? " Periodic" : "",
|
|
(status & STS_RECL) ? " Recl" : "",
|
|
(status & STS_HALT) ? " Halt" : "",
|
|
(status & STS_IAA) ? " IAA" : "",
|
|
(status & STS_FATAL) ? " FATAL" : "",
|
|
(status & STS_FLR) ? " FLR" : "",
|
|
(status & STS_PCD) ? " PCD" : "",
|
|
(status & STS_ERR) ? " ERR" : "",
|
|
(status & STS_INT) ? " INT" : ""
|
|
);
|
|
|
|
s_printf(" status port: %x\n", statusp);
|
|
}
|
|
|
|
#else
|
|
|
|
//#define s_printf(a...) do{}while(0)
|
|
#define s_printf(a...)
|
|
#define log_status(a)
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
static s32 __usbstorage_reset(usbstorage_handle *dev,int hard_reset);
|
|
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
|
|
static s32 __usbstorage_start_stop(usbstorage_handle *dev, u8 lun, u8 start_stop);
|
|
|
|
// ehci driver has its own timeout.
|
|
static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u32 wLength, void *rpData)
|
|
{
|
|
return USB_WriteBlkMsg(dev->usb_fd, bEndpoint, wLength, rpData);
|
|
}
|
|
|
|
static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
|
|
{
|
|
return USB_WriteCtrlMsg(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData);
|
|
}
|
|
|
|
|
|
|
|
static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
|
|
{
|
|
s32 retval = USBSTORAGE_OK;
|
|
|
|
if(cbLen == 0 || cbLen > 16 || !dev->buffer)
|
|
return -EINVAL;
|
|
memset(dev->buffer, 0, CBW_SIZE);
|
|
|
|
((u32*)dev->buffer)[0]=cpu_to_le32(CBW_SIGNATURE);
|
|
((u32*)dev->buffer)[1]=cpu_to_le32(dev->tag);
|
|
((u32*)dev->buffer)[2]=cpu_to_le32(len);
|
|
dev->buffer[12] = flags;
|
|
dev->buffer[13] = lun;
|
|
|
|
// linux usb/storage/protocol.c seems to say only difference is padding
|
|
// and fixed cw size
|
|
/*
|
|
if(dev->ata_protocol)
|
|
dev->buffer[14] = 12;
|
|
else
|
|
dev->buffer[14] = (cbLen > 6 ? 0x10 : 6);
|
|
|
|
dev->buffer[14] = (cb[0] > 0x1f ? 0x0A : 0x06);
|
|
*/
|
|
dev->buffer[14] = (cbLen > 6 ? 10 : 6);
|
|
//debug_printf("send cb of size %d\n",dev->buffer[14]);
|
|
memcpy(dev->buffer + 15, cb, cbLen);
|
|
//hexdump(dev->buffer,CBW_SIZE);
|
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
|
|
|
|
if(retval == CBW_SIZE) return USBSTORAGE_OK;
|
|
else if(retval >= 0) return USBSTORAGE_ESHORTWRITE;
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
|
|
{
|
|
s32 retval = USBSTORAGE_OK;
|
|
u32 signature, tag, _dataResidue, _status;
|
|
|
|
|
|
memset(dev->buffer, 0xff, CSW_SIZE);
|
|
|
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer);
|
|
//print_hex_dump_bytes("csv resp:",DUMP_PREFIX_OFFSET,dev->buffer,CSW_SIZE);
|
|
|
|
|
|
if(retval >= 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD;
|
|
if(retval < 0) return retval;
|
|
|
|
signature = le32_to_cpu(((u32*)dev->buffer)[0]);
|
|
tag = le32_to_cpu(((u32*)dev->buffer)[1]);
|
|
_dataResidue = le32_to_cpu(((u32*)dev->buffer)[2]);
|
|
_status = dev->buffer[12];
|
|
//debug_printf("csv status: %d\n",_status);
|
|
if(signature != CSW_SIGNATURE) {
|
|
// BUG();
|
|
return USBSTORAGE_ESIGNATURE;
|
|
}
|
|
|
|
if(dataResidue != NULL)
|
|
*dataResidue = _dataResidue;
|
|
if(status != NULL)
|
|
*status = _status;
|
|
|
|
if(tag != dev->tag) return USBSTORAGE_ETAG;
|
|
|
|
dev->tag=((dev->tag+2) & 0xffff) | (dev->tag & 0xffff0000);
|
|
//dev->tag++;
|
|
|
|
return USBSTORAGE_OK;
|
|
}
|
|
|
|
extern u32 usb_timeout;
|
|
|
|
static int is_read_write=0;
|
|
|
|
|
|
static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue, s8 retries)
|
|
{
|
|
s32 retval = USBSTORAGE_OK;
|
|
|
|
u8 status = 0;
|
|
u32 dataResidue = 0;
|
|
u32 thisLen;
|
|
u32 pstatus;
|
|
|
|
u8 *buffer2=buffer;
|
|
u32 len2=len;
|
|
|
|
int retries2=0;
|
|
int t;
|
|
|
|
|
|
// s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
|
|
|
|
unplug_device=0;
|
|
|
|
|
|
do
|
|
{
|
|
|
|
// if(unplug_device) {return -ENODEV;}
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV) {unplug_device=1;break;}
|
|
|
|
|
|
if(retval < 0 /*&& retval!=USBSTORAGE_ESTATUS*/)
|
|
{
|
|
|
|
retval=__usbstorage_reset(dev,0);
|
|
|
|
|
|
if(retval >=0) ehci_msleep(5); else ehci_msleep(60);
|
|
pstatus = ehci_readl(&ehci->regs->port_status[current_port]);
|
|
|
|
retries2++;
|
|
if(retval<0)
|
|
{
|
|
if(retries2>2) {unplug_device=1;break;} else {ehci_msleep(10);continue;}
|
|
} else retries2=0;
|
|
|
|
/////
|
|
|
|
//if(retval==-ENODEV) {unplug_device=1;return -ENODEV;}
|
|
}
|
|
retries--;
|
|
//if(retval<0) continue; // nuevo
|
|
|
|
buffer=buffer2;
|
|
len=len2;
|
|
|
|
if(write)
|
|
{
|
|
t=usb_timeout;
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
|
|
|
|
usb_timeout=t;
|
|
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV)
|
|
break;
|
|
|
|
if(retval < 0)
|
|
continue;//reset+retry
|
|
|
|
while(len > 0)
|
|
{
|
|
thisLen=len;
|
|
|
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, buffer);
|
|
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV) break;
|
|
|
|
if(retval<0) { retval = USBSTORAGE_EDATARESIDUE;break;}
|
|
|
|
if(retval != thisLen && len>0)
|
|
{
|
|
retval = USBSTORAGE_EDATARESIDUE;
|
|
break;
|
|
}
|
|
|
|
len -= retval;
|
|
buffer += retval;
|
|
}
|
|
|
|
if(retval < 0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
t=usb_timeout;
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
|
|
|
|
usb_timeout=t;
|
|
|
|
|
|
|
|
if(retval<0)
|
|
{
|
|
s_printf("__send_cbw ret %i\n", retval);
|
|
log_status("_send_cbw");
|
|
}
|
|
|
|
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV)
|
|
break;
|
|
|
|
if(retval < 0)
|
|
continue; //reset+retry
|
|
|
|
while(len > 0)
|
|
{
|
|
thisLen=len; //if(thisLen>8192) thisLen=8192;
|
|
|
|
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, buffer);
|
|
|
|
|
|
if(retval<0)
|
|
{
|
|
s_printf("__USB_BlkMsgTimeout %i\n", retval);
|
|
log_status("__USB_BlkMsgTimeout");
|
|
}
|
|
|
|
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV) break;
|
|
if(retval<0) { retval = USBSTORAGE_EDATARESIDUE;break;}
|
|
|
|
|
|
|
|
if(retval != thisLen)
|
|
{
|
|
retval = USBSTORAGE_EDATARESIDUE;
|
|
break;
|
|
}
|
|
|
|
len -= retval;
|
|
buffer += retval;
|
|
}
|
|
|
|
if(retval < 0)
|
|
continue;
|
|
}
|
|
|
|
t=usb_timeout;
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
retval = __read_csw(dev, &status, &dataResidue);
|
|
|
|
|
|
if(retval<0)
|
|
{
|
|
s_printf("__read_csw %i\n", retval);
|
|
log_status("__read_csw");
|
|
}
|
|
|
|
|
|
if(retval==-ENODEV) {usb_timeout=t;break;}
|
|
|
|
if(retval<0)
|
|
{
|
|
USB_ClearHalt(dev->usb_fd, dev->ep_in);
|
|
set_toggle(dev->usb_fd, dev->ep_in,0);
|
|
|
|
retval = __read_csw(dev, &status, &dataResidue);
|
|
}
|
|
|
|
usb_timeout=t;
|
|
|
|
if(retval==-ETIMEDOUT || retval==-ENODEV) break;
|
|
|
|
if(dataResidue && is_read_write)
|
|
{
|
|
status=1;
|
|
}
|
|
|
|
|
|
if(retval>=0 && is_read_write!=0 && status!=0)
|
|
{
|
|
retval = USBSTORAGE_ESTATUS; // if read/write bad status repeat the read/write
|
|
}
|
|
|
|
|
|
if(retval < 0)
|
|
continue;
|
|
|
|
retval = USBSTORAGE_OK;
|
|
} while(retval < 0 && retries > 0);
|
|
|
|
// force unplug
|
|
if(retval < 0) {unplug_device=1;}
|
|
|
|
|
|
if(retval>=0) unplug_device=0;
|
|
|
|
|
|
if(_status != NULL)
|
|
*_status = status;
|
|
if(_dataResidue != NULL)
|
|
*_dataResidue = dataResidue;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static s32 __usbstorage_start_stop(usbstorage_handle *dev, u8 lun, u8 start_stop)
|
|
{
|
|
#if 0
|
|
s32 retval;
|
|
u8 cmd[16];
|
|
|
|
u8 status = 0;
|
|
|
|
memset(cmd, 0, sizeof(cmd));
|
|
cmd[0] = SCSI_START_STOP;
|
|
cmd[1] = (lun << 5) | 1;
|
|
cmd[4] = start_stop & 3;
|
|
cmd[5] = 0;
|
|
//memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
|
|
retval = __cycle(dev, lun, NULL, 0, cmd, 6, 0, &status, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
// if(retval < 0) goto error;
|
|
|
|
|
|
//error:
|
|
return retval;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
|
|
{
|
|
s32 retval;
|
|
u8 cmd[16];
|
|
u8 *sense= ((u8 *)dev->buffer)+2048;//USB_Alloc(SCSI_SENSE_REPLY_SIZE);
|
|
u8 status = 0;
|
|
memset(cmd, 0, sizeof(cmd));
|
|
cmd[0] = SCSI_TEST_UNIT_READY;
|
|
//int n;
|
|
|
|
if(!sense) return -ENOMEM;
|
|
|
|
|
|
retval = __cycle(dev, lun, NULL, 0, cmd, 6, 1, &status, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
//retval = __cycle(dev, lun, NULL, 0, cmd, 1, 1, &status, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
|
|
|
|
//if(retval<0)
|
|
s_printf(" SCSI_TEST_UNIT_READY ret %i\n", retval);
|
|
|
|
|
|
|
|
if(retval==-ENODEV) goto error;
|
|
//if(retval<0) goto error;
|
|
|
|
if(status != 0 || retval<0 )
|
|
{
|
|
cmd[0] = SCSI_REQUEST_SENSE;
|
|
cmd[1] = lun << 5;
|
|
cmd[4] = SCSI_SENSE_REPLY_SIZE;
|
|
cmd[5] = 0;
|
|
memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
|
|
if(retval == USBSTORAGE_ETIMEDOUT) usb_timeout=2500*1000;
|
|
else usb_timeout=10000*1000;
|
|
|
|
retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
|
|
|
|
s_printf(" SCSI_REQUEST_SENSE ret %i\n", retval);
|
|
|
|
|
|
if(retval < 0) goto error;
|
|
|
|
status = sense[2] & 0x0F;
|
|
|
|
s_printf(" SCSI_REQUEST_SENSE status %x\n", status);
|
|
|
|
|
|
if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR)
|
|
retval = USBSTORAGE_ESENSE;
|
|
}
|
|
error:
|
|
// USB_Free(sense);
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
static s32 __usbstorage_reset(usbstorage_handle *dev,int hard_reset)
|
|
{
|
|
s32 retval=-1;
|
|
u32 old_usb_timeout=usb_timeout;
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
u32 status;
|
|
u8 conf;
|
|
|
|
|
|
status = ehci_readl(&ehci->regs->port_status[dev->usb_fd->port]);
|
|
|
|
// device unplugged
|
|
if (!(PORT_CONNECT & status))
|
|
{
|
|
unplug_device=1;
|
|
usb_timeout=old_usb_timeout;
|
|
return -ENODEV;
|
|
}
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
|
|
if(use_reset_bulk)
|
|
{
|
|
retval = __USB_CtrlMsgTimeout(dev,
|
|
(USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE),
|
|
USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
|
|
|
|
s_printf("usbstorage reset: BULK RESET %i\n",retval);
|
|
|
|
/* gives device enough time to process the reset */
|
|
ehci_msleep(60);
|
|
}
|
|
else
|
|
{
|
|
USB_ClearHalt(dev->usb_fd, 0);
|
|
ehci_msleep(5);
|
|
retval=0;
|
|
}
|
|
|
|
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
/* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
|
|
if(retval < 0)
|
|
{
|
|
ehci_msleep(50);
|
|
USB_ClearHalt(dev->usb_fd, 0);
|
|
ehci_msleep(5);
|
|
goto end;
|
|
}
|
|
|
|
|
|
retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
|
|
ehci_msleep(5);
|
|
|
|
|
|
s_printf("usbstorage reset: clearhalt in ret %i\n",retval);
|
|
|
|
|
|
if(retval < 0)
|
|
goto end;
|
|
|
|
retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
|
|
ehci_msleep(5);
|
|
|
|
|
|
s_printf("usbstorage reset: clearhalt out ret %i\n",retval);
|
|
|
|
|
|
if(retval < 0)
|
|
goto end;
|
|
|
|
ehci_msleep(10);
|
|
retval=USB_GetConfiguration(dev->usb_fd, &conf); // for test it works
|
|
|
|
|
|
s_printf("usbstorage reset: USB_GetConfiguration ret %i\n",retval);
|
|
|
|
|
|
if(retval < 0)
|
|
goto end;
|
|
|
|
|
|
s_printf("reset ok\n");
|
|
|
|
|
|
usb_timeout=old_usb_timeout;
|
|
return retval;
|
|
|
|
end:
|
|
|
|
usb_timeout=old_usb_timeout;
|
|
|
|
unplug_device=1; // force the unplug method
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
int my_memcmp(char *a, char *b, int size_b)
|
|
{
|
|
int n;
|
|
|
|
for(n=0;n<size_b;n++)
|
|
{
|
|
if(*a!=*b) return 1;
|
|
a++;b++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
s32 try_status=0;
|
|
|
|
struct _device_data
|
|
{
|
|
u32 mounted;
|
|
u8 lun;
|
|
u8 use_maxlun;
|
|
u8 bDeviceClass;
|
|
u8 bDeviceSubClass;
|
|
u16 idVendor;
|
|
u16 idProduct;
|
|
u8 iManufacturer;
|
|
u8 iProduct;
|
|
u8 iSerialNumber;
|
|
u8 interface;
|
|
u8 ep_in;
|
|
u8 ep_out;
|
|
|
|
u16 pad2;
|
|
|
|
|
|
} ATTRIBUTE_PACKED _old_device={0};
|
|
|
|
|
|
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd)
|
|
{
|
|
s32 retval = -1;
|
|
u8 conf=0;//,*max_lun = NULL;
|
|
u32 iConf, iInterface, iEp;
|
|
static usb_devdesc udd;
|
|
usb_configurationdesc *ucd;
|
|
usb_interfacedesc *uid;
|
|
usb_endpointdesc *ued;
|
|
|
|
|
|
__lun= 16; // select bad LUN
|
|
|
|
//max_lun = USB_Alloc(1);
|
|
//if(max_lun==NULL) return -ENOMEM;
|
|
|
|
//memset(dev, 0, sizeof(*dev));
|
|
|
|
dev->tag = TAG_START;
|
|
|
|
dev->usb_fd = fd;
|
|
|
|
|
|
udd.configurations=NULL;
|
|
|
|
retval = USB_GetDescriptors(dev->usb_fd, &udd);
|
|
|
|
|
|
s_printf("USBStorage_Open(): USB_GetDescriptors %i\n",retval);
|
|
|
|
log_status("after USB_GetDescriptors");
|
|
|
|
|
|
|
|
if(retval < 0)
|
|
goto free_and_return;
|
|
|
|
// test device changed without unmount (prevent device write corruption)
|
|
if(ums_init_done)
|
|
{
|
|
if(_old_device.bDeviceClass!=udd.bDeviceClass ||
|
|
_old_device.bDeviceSubClass!=udd.bDeviceSubClass ||
|
|
_old_device.idVendor!=udd.idVendor ||
|
|
_old_device.idProduct!=udd.idProduct ||
|
|
_old_device.iManufacturer!=udd.iManufacturer ||
|
|
_old_device.iProduct!=udd.iProduct ||
|
|
_old_device.iSerialNumber!=udd.iSerialNumber)
|
|
{
|
|
//USB_Free(max_lun);
|
|
USB_FreeDescriptors(&udd);
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_Open(): device changed!!!\n");
|
|
|
|
#endif
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
_old_device.bDeviceClass=udd.bDeviceClass;
|
|
_old_device.bDeviceSubClass=udd.bDeviceSubClass;
|
|
_old_device.idVendor=udd.idVendor;
|
|
_old_device.idProduct=udd.idProduct;
|
|
_old_device.iManufacturer=udd.iManufacturer;
|
|
_old_device.iProduct=udd.iProduct;
|
|
_old_device.iSerialNumber=udd.iSerialNumber;
|
|
|
|
|
|
try_status=-128;
|
|
for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
|
|
{
|
|
ucd = &udd.configurations[iConf];
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_Open(): ucd %i Power %i mA\n",iConf, ((u32) ucd->bMaxPower)*2);
|
|
|
|
#endif
|
|
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
|
|
{
|
|
uid = &ucd->interfaces[iInterface];
|
|
// debug_printf("interface %d, class:%x subclass %x protocol %x\n",iInterface,uid->bInterfaceClass,uid->bInterfaceSubClass, uid->bInterfaceProtocol);
|
|
if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE && /*
|
|
(uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS
|
|
|| uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS
|
|
|| uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS
|
|
|| uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS
|
|
|| uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS
|
|
|| uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) && */
|
|
uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY && uid->bNumEndpoints>=2)
|
|
{
|
|
|
|
dev->ata_protocol = 0;
|
|
if(uid->bInterfaceSubClass != MASS_STORAGE_SCSI_COMMANDS || uid->bInterfaceSubClass != MASS_STORAGE_RBC_COMMANDS)
|
|
dev->ata_protocol = 1;
|
|
|
|
|
|
s_printf("USBStorage_Open(): interface subclass %i ata_prot %i \n",uid->bInterfaceSubClass, dev->ata_protocol);
|
|
|
|
|
|
dev->ep_in = dev->ep_out = 0;
|
|
for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
|
|
{
|
|
ued = &uid->endpoints[iEp];
|
|
if(ued->bmAttributes != USB_ENDPOINT_BULK)
|
|
continue;
|
|
|
|
if((ued->bEndpointAddress & USB_ENDPOINT_IN) && !dev->ep_in && ued->bEndpointAddress!=0)
|
|
{dev->ep_in = ued->bEndpointAddress;
|
|
#ifdef MEM_PRINT
|
|
s_printf("In Point: %i\n", (u32) ued->wMaxPacketSize);
|
|
#endif
|
|
}
|
|
else
|
|
if(!dev->ep_out && ued->bEndpointAddress!=0)
|
|
{
|
|
dev->ep_out = ued->bEndpointAddress;
|
|
|
|
s_printf("Out Point: %i\n", (u32) ued->wMaxPacketSize);
|
|
|
|
}
|
|
}
|
|
if(dev->ep_in != 0 && dev->ep_out != 0)
|
|
{
|
|
#ifdef MEM_PRINT
|
|
s_printf("ep_in %x ep_out %x\n", (u32) dev->ep_in, (u32) dev->ep_out);
|
|
|
|
#endif
|
|
_old_device.ep_in=dev->ep_in;
|
|
_old_device.ep_out=dev->ep_out;
|
|
|
|
dev->configuration = ucd->bConfigurationValue;
|
|
dev->interface = uid->bInterfaceNumber;
|
|
_old_device.interface=dev->interface;
|
|
dev->altInterface = uid->bAlternateSetting;
|
|
|
|
goto found;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
if(uid->endpoints != NULL)
|
|
USB_Free(uid->endpoints);uid->endpoints= NULL;
|
|
if(uid->extra != NULL)
|
|
USB_Free(uid->extra);uid->extra=NULL;
|
|
|
|
if(uid->bInterfaceClass == USB_CLASS_HUB)
|
|
{
|
|
retval = USBSTORAGE_ENOINTERFACE;
|
|
try_status= -20000;
|
|
|
|
USB_FreeDescriptors(&udd);
|
|
|
|
goto free_and_return;
|
|
}
|
|
|
|
if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
|
|
uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY && uid->bNumEndpoints>=2)
|
|
{
|
|
try_status= -(10000+uid->bInterfaceSubClass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
s_printf("USBStorage_Open(): cannot find any interface!!!\n");
|
|
|
|
|
|
USB_FreeDescriptors(&udd);
|
|
retval = USBSTORAGE_ENOINTERFACE;
|
|
//debug_printf("cannot find any interface\n");
|
|
goto free_and_return;
|
|
|
|
found:
|
|
USB_FreeDescriptors(&udd);
|
|
|
|
retval = USBSTORAGE_EINIT;
|
|
|
|
|
|
try_status=-1201;
|
|
|
|
|
|
s_printf("USBStorage_Open(): conf: %x altInterface: %x\n", dev->configuration, dev->altInterface);
|
|
|
|
if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
|
|
{
|
|
s_printf("USB_GetConfiguration() Error. Continue.\n");
|
|
//goto free_and_return;
|
|
}
|
|
s_printf("Actual conf: %x next conf: %x\n",conf, dev->configuration);
|
|
try_status=-1202;
|
|
if(USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
|
|
{
|
|
s_printf("USB_SetConfiguration() Error\n");
|
|
//goto free_and_return;
|
|
}
|
|
|
|
try_status=-1203;
|
|
if(/*dev->altInterface != 0 &&*/ USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
|
|
{
|
|
s_printf("USB_SetAlternativeInterface() Error. Continue\n");
|
|
//goto free_and_return;
|
|
}
|
|
s_printf("USB_SetConfiguration() & USB_SetAlternativeInterface() OK\n");
|
|
/*
|
|
if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
|
|
goto free_and_return;
|
|
try_status=-1202;
|
|
|
|
#ifdef MEM_PRINT
|
|
log_status("after USB_GetConfiguration");
|
|
#endif
|
|
|
|
#ifdef MEM_PRINT
|
|
if(conf != dev->configuration)
|
|
s_printf("USBStorage_Open(): changing conf from %x\n", conf);
|
|
|
|
#endif
|
|
|
|
usb_timeout=10000*1000;
|
|
if((conf != dev->configuration || (force_flags & 2)) && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
|
|
goto free_and_return;
|
|
|
|
try_status=-1203;
|
|
if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
|
|
goto free_and_return;
|
|
|
|
usb_timeout=1000*1000;
|
|
try_status=-1204;
|
|
|
|
#ifdef MEM_PRINT
|
|
log_status("Before USBStorage_Reset");
|
|
#endif
|
|
retval = USBStorage_Reset(dev);
|
|
//retval=0;
|
|
//retval =__usbstorage_reset(dev, 1);
|
|
#ifdef MEM_PRINT
|
|
log_status("After USBStorage_Reset");
|
|
#endif
|
|
if(retval < 0)
|
|
goto free_and_return;
|
|
*/
|
|
u8 max_lun=0;
|
|
retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, sizeof(max_lun), &max_lun);
|
|
if(retval < 0 )
|
|
{
|
|
s_printf("Get_Max_Lun(): err, default max_lun=8\n");
|
|
dev->max_lun = 8;
|
|
}
|
|
else
|
|
{
|
|
dev->max_lun = (max_lun+1);
|
|
s_printf("Get_Max_Lun(): OK: %i\n",dev->max_lun);
|
|
}
|
|
|
|
|
|
/* if(retval == USBSTORAGE_ETIMEDOUT)*/
|
|
|
|
/* NOTE: from usbmassbulk_10.pdf "Devices that do not support multiple LUNs may STALL this command." */
|
|
// dev->max_lun = 8; // max_lun can be from 1 to 16, but some devices do not support lun
|
|
|
|
retval = USBSTORAGE_OK;
|
|
|
|
/*if(dev->max_lun == 0)
|
|
dev->max_lun++;*/
|
|
|
|
/* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
|
|
/*
|
|
* Some devices (i.e. Iomega Zip100) need this -- apparently
|
|
* the bulk pipes get STALLed when the GetMaxLUN request is
|
|
* processed. This is, in theory, harmless to all other devices
|
|
* (regardless of if they stall or not).
|
|
*/
|
|
//USB_ClearHalt(dev->usb_fd, dev->ep_in);
|
|
//USB_ClearHalt(dev->usb_fd, dev->ep_out);
|
|
|
|
if(dev->buffer == NULL)
|
|
dev->buffer = (void *) ((((u32) USB_Alloc(MAX_TRANSFER_SIZE+32))+31) & ~31);
|
|
|
|
if(dev->buffer == NULL) {retval = -ENOMEM;try_status=-1205;}
|
|
else retval = USBSTORAGE_OK;
|
|
|
|
free_and_return:
|
|
|
|
usb_timeout=1000*1000;
|
|
|
|
if(retval < 0)
|
|
{
|
|
/*
|
|
// Never free dev->buffer or destroy the dev info
|
|
if(dev->buffer != NULL)
|
|
USB_Free(dev->buffer);
|
|
memset(dev, 0, sizeof(*dev));
|
|
*/
|
|
|
|
|
|
s_printf("USBStorage_Open(): try_status %i\n",try_status);
|
|
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
s_printf("USBStorage_Open(): OK, return 0\n");
|
|
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void my_sprint(char *cad, char *s);
|
|
|
|
s32 USBStorage_Close(usbstorage_handle *dev)
|
|
{
|
|
|
|
// Never free dev->buffer or destroy the dev info
|
|
|
|
/*if(dev->buffer != NULL)
|
|
USB_Free(dev->buffer);
|
|
dev->buffer=NULL;
|
|
*/
|
|
//memset(dev, 0, sizeof(*dev));
|
|
|
|
//my_sprint("USBStorage_Close()", NULL);
|
|
return 0;
|
|
}
|
|
|
|
s32 USBStorage_Reset(usbstorage_handle *dev)
|
|
{
|
|
s32 retval;
|
|
|
|
retval = __usbstorage_reset(dev,0);
|
|
|
|
return retval;
|
|
}
|
|
|
|
s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
|
|
{
|
|
|
|
return dev->max_lun;
|
|
}
|
|
|
|
|
|
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
|
|
{
|
|
s32 retval;
|
|
|
|
|
|
if(lun >= dev->max_lun)
|
|
return -EINVAL;
|
|
usb_timeout=1000*1000;
|
|
|
|
|
|
retval= __usbstorage_start_stop(dev, lun, 1);
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf(" start_stop cmd ret %i\n",retval);
|
|
#endif
|
|
if(retval < 0)
|
|
goto ret;
|
|
usb_timeout=20000*1000;
|
|
retval = __usbstorage_clearerrors(dev, lun);
|
|
if(retval < 0)
|
|
goto ret;
|
|
usb_timeout=1000*1000;
|
|
|
|
retval = USBStorage_Inquiry(dev, lun);
|
|
|
|
s_printf(" Inquiry ret %i\n",retval);
|
|
|
|
if(retval>=0)
|
|
{
|
|
s_printf(" Device Type: %x\n", *(((u8 *)dev->buffer)+2048) & 31);
|
|
}
|
|
|
|
if(retval < 0)
|
|
goto ret;
|
|
retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], &dev->n_sector[lun]);
|
|
|
|
s_printf(" ReadCapacity ret %i sector_size: %u sectors: %u\n",retval,dev->sector_size[lun],dev->n_sector[lun]);
|
|
|
|
if(dev->sector_size[lun]<512 || dev->n_sector[lun]<10) retval=-33;
|
|
|
|
ret:
|
|
usb_timeout=1000*1000;
|
|
|
|
return retval;
|
|
}
|
|
|
|
s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun)
|
|
{
|
|
int n;
|
|
s32 retval;
|
|
u8 cmd[] = {SCSI_INQUIRY, lun << 5,0,0,36,0};
|
|
u8 *response = ((u8 *)dev->buffer)+2048; //USB_Alloc(36);
|
|
|
|
if(!response) return -ENOMEM;
|
|
for(n=0;n<2;n++)
|
|
{
|
|
|
|
|
|
memset(response,0,36);
|
|
|
|
retval = __cycle(dev, lun, response, 36, cmd, 6, 0, NULL, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
if(retval>=0) break;
|
|
|
|
}
|
|
if(retval>=0)
|
|
{
|
|
switch(*response & 31)
|
|
{
|
|
// info from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
|
|
case 5: // CDROM
|
|
case 7: // optical memory device (e.g., some optical disks)
|
|
is_dvd=1;
|
|
break;
|
|
default:
|
|
is_dvd=0;
|
|
break;
|
|
}
|
|
}
|
|
//USB_Free(response);
|
|
|
|
return retval;
|
|
}
|
|
s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
|
|
{
|
|
s32 retval;
|
|
u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
|
|
u8 *response = ((u8 *)dev->buffer)+2048; //USB_Alloc(8);
|
|
u32 val;
|
|
if(!response) return -ENOMEM;
|
|
|
|
retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL, USBSTORAGE_CYCLE_RETRIES);
|
|
if(retval >= 0)
|
|
{
|
|
|
|
memcpy(&val, response, 4);
|
|
if(n_sectors != NULL)
|
|
*n_sectors = be32_to_cpu(val);
|
|
memcpy(&val, response + 4, 4);
|
|
if(sector_size != NULL)
|
|
*sector_size = be32_to_cpu(val);
|
|
if(be32_to_cpu(val)==2048)is_dvd=1;
|
|
retval = USBSTORAGE_OK;
|
|
}
|
|
// USB_Free(response);
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
static s32 __USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
|
|
{
|
|
u8 status = 0;
|
|
s32 retval;
|
|
u8 cmd[] = {
|
|
SCSI_READ_10,
|
|
(lun << 5),
|
|
sector >> 24,
|
|
sector >> 16,
|
|
sector >> 8,
|
|
sector,
|
|
0,
|
|
n_sectors >> 8,
|
|
n_sectors,
|
|
0
|
|
};
|
|
|
|
if(lun >= dev->max_lun || dev->sector_size[lun] == 0 || !dev)
|
|
return -EINVAL;
|
|
is_read_write=1;
|
|
retval = __cycle(dev, lun, buffer, ((u32) n_sectors) * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL, 6);
|
|
is_read_write=0;
|
|
if(retval > 0 && status != 0)
|
|
retval = USBSTORAGE_ESTATUS;
|
|
return retval;
|
|
}
|
|
|
|
static s32 __USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
|
|
{
|
|
u8 status = 0;
|
|
s32 retval;
|
|
u8 cmd[] = {
|
|
SCSI_WRITE_10,
|
|
(lun << 5) | 8, // LUN & FUA (Force Unit Access to avoid the cache),
|
|
sector >> 24,
|
|
sector >> 16,
|
|
sector >> 8,
|
|
sector,
|
|
0,
|
|
n_sectors >> 8,
|
|
n_sectors,
|
|
0
|
|
};
|
|
|
|
if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
|
|
return -EINVAL;
|
|
|
|
is_read_write=1;
|
|
retval = __cycle(dev, lun, (u8 *)buffer, ((u32) n_sectors )* dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL,6);
|
|
is_read_write=0;
|
|
if(retval > 0 && status != 0)
|
|
retval = USBSTORAGE_ESTATUS;
|
|
return retval;
|
|
}
|
|
|
|
s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
|
|
{
|
|
u32 max_sectors=n_sectors;
|
|
u32 sectors;
|
|
s32 ret=-1;
|
|
|
|
if(((u32) n_sectors) * dev->sector_size[lun]>64*1024) max_sectors= 64*1024/dev->sector_size[lun]; // surely it fix a problem with some devices...
|
|
|
|
while(n_sectors>0)
|
|
{
|
|
|
|
sectors=n_sectors>max_sectors ? max_sectors: n_sectors;
|
|
ret=__USBStorage_Read(dev, lun, sector, sectors, buffer);
|
|
if(ret<0) return ret;
|
|
|
|
n_sectors-=sectors;
|
|
sector+=sectors;
|
|
buffer+=sectors * dev->sector_size[lun];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
|
|
{
|
|
u32 max_sectors=n_sectors;
|
|
u32 sectors;
|
|
s32 ret=-1;
|
|
|
|
if(((u32) n_sectors) * dev->sector_size[lun]>64*1024) max_sectors=64*1024/dev->sector_size[lun]; // surely it fix a problem with some devices...
|
|
|
|
while(n_sectors>0)
|
|
{
|
|
|
|
sectors=n_sectors>max_sectors ? max_sectors: n_sectors;
|
|
ret=__USBStorage_Write(dev, lun, sector, sectors, buffer);
|
|
if(ret<0) return ret;
|
|
|
|
n_sectors-=sectors;
|
|
sector+=sectors;
|
|
buffer+=sectors * dev->sector_size[lun];
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
The following is for implementing the ioctl interface inpired by the disc_io.h
|
|
as used by libfat
|
|
|
|
This opens the first lun of the first usbstorage device found.
|
|
*/
|
|
|
|
|
|
|
|
// temp function before libfat is available */
|
|
s32 USBStorage_Try_Device(struct ehci_device *fd)
|
|
{
|
|
int maxLun,j,retval;
|
|
int test_max_lun=1;
|
|
|
|
__vid=0;
|
|
__pid=0;
|
|
__mounted = 0;
|
|
__lun = 0;
|
|
|
|
try_status=-120;
|
|
// swi_mload_led_on();
|
|
if(USBStorage_Open(&__usbfd, fd) < 0)
|
|
return -EINVAL;
|
|
|
|
|
|
maxLun= 1;
|
|
__usbfd.max_lun = 1;
|
|
|
|
j=0;
|
|
|
|
// fast re-mount
|
|
if(_old_device.mounted)
|
|
{
|
|
if(_old_device.use_maxlun || (force_flags & 1))
|
|
{
|
|
__usbfd.max_lun = 0;
|
|
usb_timeout=10000*1000;
|
|
retval = __USB_CtrlMsgTimeout(&__usbfd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE),
|
|
USBSTORAGE_GET_MAX_LUN, 0, __usbfd.interface, 1, &__usbfd.max_lun);
|
|
usb_timeout=1000*1000;
|
|
if(retval < 0)
|
|
{
|
|
__usbfd.max_lun = 1;
|
|
goto bad_mount;
|
|
}
|
|
else {__usbfd.max_lun++;}
|
|
|
|
|
|
|
|
}
|
|
j=_old_device.lun;
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf("Fast USBStorage_MountLUN %i#\n", j);
|
|
#endif
|
|
retval = USBStorage_MountLUN(&__usbfd, j);
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_MountLUN: ret %i\n", retval);
|
|
#endif
|
|
if(retval == USBSTORAGE_ETIMEDOUT || retval==-ENODEV /*&& test_max_lun==0*/)
|
|
{
|
|
USBStorage_Reset(&__usbfd);
|
|
try_status=-121;
|
|
__mounted = 0;
|
|
USBStorage_Close(&__usbfd);
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if(retval < 0) goto bad_mount;
|
|
|
|
__mounted = 1;
|
|
__lun = j;
|
|
usb_timeout=1000*1000;
|
|
try_status=0;
|
|
// swi_mload_led_off();
|
|
|
|
return 0;
|
|
}
|
|
|
|
_old_device.use_maxlun=0;
|
|
//for(j = 0; j < maxLun; j++)
|
|
while(1)
|
|
{
|
|
if(!(force_flags & 1) || j!=0 || !test_max_lun)
|
|
{
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_MountLUN %i#\n", j);
|
|
#endif
|
|
retval = USBStorage_MountLUN(&__usbfd, j);
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_MountLUN: ret %i\n", retval);
|
|
#endif
|
|
|
|
|
|
if((retval == USBSTORAGE_ETIMEDOUT || retval==-ENODEV) && j!=0)
|
|
{
|
|
usb_timeout=1000*1000;
|
|
USBStorage_Reset(&__usbfd);
|
|
try_status=-121;
|
|
__mounted = 0;
|
|
USBStorage_Close(&__usbfd);
|
|
return -EINVAL;
|
|
// break;
|
|
}
|
|
}
|
|
else
|
|
{retval=-1;} // force get max lun before Mount LUN
|
|
|
|
if(retval < 0)
|
|
{
|
|
if(test_max_lun)
|
|
{
|
|
unplug_device=0;
|
|
__usbfd.max_lun = 0;
|
|
|
|
usb_timeout=10000*1000;
|
|
retval = __USB_CtrlMsgTimeout(&__usbfd,
|
|
(USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE),
|
|
USBSTORAGE_GET_MAX_LUN, 0, __usbfd.interface, 1, &__usbfd.max_lun);
|
|
usb_timeout=1000*1000;
|
|
if(retval < 0 )
|
|
{__usbfd.max_lun = 1;unplug_device=0;}
|
|
else {__usbfd.max_lun++;_old_device.use_maxlun=1;}
|
|
maxLun = __usbfd.max_lun;
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBSTORAGE_GET_MAX_LUN ret %i maxlun %i\n", retval,maxLun);
|
|
#endif
|
|
if(!(force_flags & 1)) test_max_lun=0;
|
|
else if(retval >= 0 ) test_max_lun=0;
|
|
}
|
|
else j++;
|
|
|
|
if(j>=maxLun) break;
|
|
continue;
|
|
}
|
|
|
|
_old_device.mounted=1;
|
|
_old_device.lun=j;
|
|
|
|
__vid=fd->desc.idVendor;
|
|
__pid=fd->desc.idProduct;
|
|
__mounted = 1;
|
|
__lun = j;
|
|
usb_timeout=1000*1000;
|
|
try_status=0;
|
|
// swi_mload_led_off();
|
|
return 0;
|
|
}
|
|
bad_mount:
|
|
try_status=-122;
|
|
|
|
USBStorage_Reset(&__usbfd);
|
|
__mounted = 0;
|
|
USBStorage_Close(&__usbfd);
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_MountLUN fail!!!\n");
|
|
#endif
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
void USBStorage_Umount(void)
|
|
{
|
|
if(!ums_init_done) return;
|
|
/*
|
|
if(__mounted && !unplug_device)
|
|
{
|
|
if(__usbstorage_start_stop(&__usbfd, __lun, 0x0)==0) // stop
|
|
ehci_msleep(1000);
|
|
}
|
|
*/
|
|
USBStorage_Close(&__usbfd);__lun= 16;
|
|
__mounted=0;
|
|
ums_init_done=0;
|
|
unplug_device=0;
|
|
memset(&_old_device,0,sizeof(_old_device));
|
|
}
|
|
|
|
|
|
s32 USBStorage_Init(void)
|
|
{
|
|
int i;
|
|
u32 status;
|
|
int ret;
|
|
|
|
int from=0,to=0;
|
|
|
|
//debug_printf("usbstorage init %d\n", ums_init_done);
|
|
|
|
if(ums_init_done)
|
|
return 0;
|
|
|
|
ehci_writel (0, &ehci->regs->intr_enable);
|
|
ehci_int_passive_callback(NULL); // interrupt port changes detection
|
|
|
|
|
|
|
|
try_status=-100;
|
|
unplug_device=1;
|
|
__mounted=0;
|
|
use_alternative_timeout=1;
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf("\n***************************************************\nRodries ehcmodule 1.0\nUSBStorage_Init()\n***************************************************\n\n");
|
|
|
|
#endif
|
|
|
|
/*if(use_usb_port1!=0)
|
|
{
|
|
|
|
struct ehci_device *dev = &ehci->devices[0];
|
|
|
|
|
|
dev->port=0;
|
|
dev->id=0;
|
|
ret=ehci_reset_port(0);
|
|
}
|
|
*/
|
|
if(use_usb_port1==1)from=to=1;
|
|
else if(use_usb_port1==2)
|
|
{
|
|
from=0;
|
|
to=1;
|
|
}
|
|
//current_port=use_usb_port1!=0;
|
|
//for(i = use_usb_port1!=0;i<(1+(use_usb_port1!=0))/*ehci->num_port*/; i++){
|
|
for(i = from;i<=to; i++){
|
|
|
|
struct ehci_device *dev = &ehci->devices[i];
|
|
|
|
|
|
|
|
dev->port=i;
|
|
current_port=i;
|
|
|
|
if(dev->id == 0)
|
|
{
|
|
|
|
status = ehci_readl(&ehci->regs->port_status[i]);
|
|
if(!(status & 1))
|
|
ehci_adquire_usb_port(i);
|
|
|
|
status = ehci_readl(&ehci->regs->port_status[i]);
|
|
|
|
|
|
if(status & 1)
|
|
{
|
|
ret=ehci_reset_port(i);
|
|
if(ret==-1119 || ret==-1120)
|
|
{
|
|
try_status=ret;
|
|
try_status=-100;
|
|
continue;
|
|
}
|
|
ret=ehci_reset_port2(i);
|
|
ehci_msleep(20);
|
|
status=ehci_readl(&ehci->regs->port_status[i]);
|
|
|
|
if(ret<0 || (status & 0x3905)!=0x1005)
|
|
ret=ehci_reset_port(i);
|
|
|
|
|
|
}
|
|
|
|
}
|
|
if(dev->id != 0)
|
|
{
|
|
unplug_device=1;
|
|
/*
|
|
ret=ehci_reset_port(i);
|
|
if(ret==-1119 || ret==-1120)
|
|
{
|
|
try_status=ret;
|
|
continue;
|
|
}
|
|
ehci_msleep(20);
|
|
status=ehci_readl(&ehci->regs->port_status[i]);
|
|
|
|
if(ret<0 || (status & 0x3105)!=0x1005)
|
|
{
|
|
ret=ehci_reset_port2(i);
|
|
ehci_msleep(20);
|
|
status=ehci_readl(&ehci->regs->port_status[i]);
|
|
}
|
|
*/
|
|
unplug_device=1;
|
|
|
|
//if(ret>=0 && (status & 0x3105)==0x1005 )
|
|
// {
|
|
|
|
if(USBStorage_Try_Device(dev)==0)
|
|
{
|
|
ums_init_done = 1;unplug_device=0;
|
|
ehci_int_passive_callback(passive_callback_hand); // interrupt port changes detection
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
|
|
s_printf("USBStorage_Init() Ok\n");
|
|
ehci_msleep(100);
|
|
u8 *buf;
|
|
buf = (u8 *) USB_Alloc(2048);
|
|
usb_timeout=10000*1000;
|
|
extern bool enable_urb_debug;
|
|
enable_urb_debug=true;
|
|
ehci_writel (0, &ehci->regs->intr_enable);
|
|
ehci_int_passive_callback(NULL);
|
|
s_printf("Reading sector 0\n");
|
|
ret=USBStorage_Read(&__usbfd, __lun, 0, 1, buf);
|
|
ehci_int_passive_callback(passive_callback_hand);
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
enable_urb_debug=false;
|
|
usb_timeout=1000*1000;
|
|
USB_Free(buf);
|
|
if(ret<0)
|
|
s_printf("Error Reading sector 0\n");
|
|
else
|
|
s_printf("OK Reading sector 0\n");
|
|
if(ret<0)
|
|
{
|
|
ehci_release_port(i);
|
|
return -1118;
|
|
}
|
|
if(is_dvd) return i+2; // is DVD medium
|
|
return i;
|
|
// 0 -> port0 1 -> port1 2 -> dvdport0 3 -> dvdport1
|
|
}
|
|
else ehci_release_port(i);
|
|
}
|
|
// }
|
|
/*
|
|
else
|
|
{
|
|
unplug_device=1;
|
|
status = ehci_readl(&ehci->regs->port_status[i]);
|
|
if(!(status & 1))
|
|
{
|
|
ehci_adquire_usb_port(i);
|
|
s_printf("adquire port: %i\n",i);
|
|
}
|
|
status = ehci_readl(&ehci->regs->port_status[i]);
|
|
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_Init() status %x\n",status);
|
|
|
|
#endif
|
|
|
|
if(status & 1)
|
|
{
|
|
ret=ehci_reset_port2(i);
|
|
ehci_msleep(20);
|
|
status=ehci_readl(&ehci->regs->port_status[i]);
|
|
|
|
if(ret<0 || (status & 0x3105)!=0x1005)
|
|
{
|
|
|
|
ret=ehci_reset_port(i);
|
|
//status=ehci_readl(&ehci->regs->port_status[current_port]);
|
|
}
|
|
|
|
|
|
try_status=-101;
|
|
}
|
|
else
|
|
{
|
|
if(try_status==-1) try_status=-100;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
ehci_int_passive_callback(passive_callback_hand); // interrupt port changes detection
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
|
|
return try_status;
|
|
}
|
|
|
|
u32 USBStorage_Get_Capacity(u32*sector_size)
|
|
{
|
|
if(sector_size) *sector_size = 0;
|
|
if(__mounted == 1 && __lun!=16)
|
|
{
|
|
if(sector_size){
|
|
*sector_size = __usbfd.sector_size[__lun];
|
|
}
|
|
return __usbfd.n_sector[__lun];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int fast_remount(void)
|
|
{
|
|
int retval;
|
|
//u8 conf=0;
|
|
usb_devdesc udd;
|
|
|
|
if(!ums_init_done) return -1009;
|
|
|
|
// swi_mload_led_on();
|
|
retval=0;
|
|
|
|
__lun=16;
|
|
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
udd.configurations=NULL;
|
|
retval = USB_GetDescriptors(__usbfd.usb_fd, &udd);
|
|
|
|
|
|
if(_old_device.bDeviceClass!=udd.bDeviceClass ||
|
|
_old_device.bDeviceSubClass!=udd.bDeviceSubClass ||
|
|
_old_device.idVendor!=udd.idVendor ||
|
|
_old_device.idProduct!=udd.idProduct ||
|
|
_old_device.iManufacturer!=udd.iManufacturer ||
|
|
_old_device.iProduct!=udd.iProduct ||
|
|
_old_device.iSerialNumber!=udd.iSerialNumber)
|
|
{
|
|
|
|
USB_FreeDescriptors(&udd);
|
|
#ifdef MEM_PRINT
|
|
s_printf("USBStorage_Open(): device changed!!!\n");
|
|
|
|
#endif
|
|
return -1009;
|
|
}
|
|
|
|
|
|
USB_FreeDescriptors(&udd);
|
|
|
|
//if(USB_GetConfiguration(__usbfd.usb_fd, &conf) <0) return -1000;
|
|
|
|
usb_timeout=10000*1000;
|
|
|
|
if(USB_SetConfiguration(__usbfd.usb_fd, __usbfd.configuration) < 0) return -1001;
|
|
|
|
if(__usbfd.altInterface != 0 && USB_SetAlternativeInterface(__usbfd.usb_fd, __usbfd.interface, __usbfd.altInterface) < 0) return -1002;
|
|
/*
|
|
|
|
if((conf != __usbfd.configuration || (force_flags & 2)) && USB_SetConfiguration(__usbfd.usb_fd, __usbfd.configuration) < 0) return -1001;
|
|
|
|
if(__usbfd.altInterface != 0 && USB_SetAlternativeInterface(__usbfd.usb_fd, __usbfd.interface, __usbfd.altInterface) < 0) return -1002;
|
|
*/
|
|
if(use_alternative_timeout) usb_timeout=1000*1000;
|
|
else usb_timeout=200*1000;
|
|
|
|
//if( __usbstorage_reset(&__usbfd,0)<0) return -1003;
|
|
|
|
usb_timeout=1000*1000;
|
|
|
|
//if(_old_device.use_maxlun || (force_flags & 1))
|
|
{
|
|
__usbfd.max_lun = 0;
|
|
|
|
usb_timeout=10000*1000;
|
|
retval = __USB_CtrlMsgTimeout(&__usbfd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE),
|
|
USBSTORAGE_GET_MAX_LUN, 0, __usbfd.interface, 1, &__usbfd.max_lun);
|
|
usb_timeout=1000*1000;
|
|
if(retval < 0)
|
|
{
|
|
__usbfd.max_lun = 1;
|
|
__usbstorage_reset(&__usbfd,0);
|
|
return -1004;
|
|
}
|
|
else {__usbfd.max_lun++;}
|
|
|
|
|
|
}
|
|
//retval = USBStorage_MountLUN(&__usbfd, _old_device.lun);
|
|
|
|
usb_timeout=20000*1000;
|
|
retval = __usbstorage_clearerrors(&__usbfd, _old_device.lun);
|
|
#ifdef MEM_PRINT
|
|
// s_printf(" Clear error ret %i\n",retval);
|
|
#endif
|
|
usb_timeout=1000*1000;
|
|
if(retval<0) return -1005;
|
|
|
|
|
|
retval = USBStorage_Inquiry(&__usbfd, _old_device.lun);
|
|
#ifdef MEM_PRINT
|
|
// s_printf(" Inquiry ret %i\n",retval);
|
|
#endif
|
|
|
|
|
|
if(retval<0) return -1006;
|
|
|
|
__lun=_old_device.lun;
|
|
__mounted=1;
|
|
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
int unplug_procedure(void)
|
|
{
|
|
int retval=1;
|
|
u32 status;
|
|
|
|
current_port=use_usb_port1!=0;
|
|
if(unplug_device!=0 )
|
|
{
|
|
|
|
// unplug detection method
|
|
|
|
status=ehci_readl(&ehci->regs->port_status[current_port]);
|
|
if(!(status & 1))
|
|
{
|
|
/*
|
|
int n;
|
|
for(n=0;n<3;n++)
|
|
{
|
|
swi_mload_led_on();ehci_msleep(100);swi_mload_led_off();ehci_msleep(100);
|
|
}
|
|
ehci_msleep(500);
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
ehci_writel (0, &ehci->regs->intr_enable); // disable interrupts
|
|
ehci_int_passive_callback(NULL);
|
|
|
|
|
|
if(1)
|
|
{
|
|
int ret;
|
|
|
|
|
|
ret=ehci_reset_port2(current_port);
|
|
//if(ret<0) ehci_reset_port(current_port);
|
|
|
|
if(ret<0) ret=ehci_reset_port2(current_port);
|
|
|
|
|
|
ehci_msleep(60);
|
|
status=ehci_readl(&ehci->regs->port_status[current_port]);
|
|
|
|
#ifdef MEM_PRINT
|
|
|
|
//s_printf("Unplug: reset_port ret %i port status %x\n", ret, status);
|
|
s_printf("Unplug: reset %i status %x\n", ret, status);
|
|
|
|
#endif
|
|
|
|
unplug_device=1;
|
|
|
|
if(ret>=0 && (status & 0x3105)==0x1005 )
|
|
{
|
|
|
|
|
|
/*if(__usbfd.buffer != NULL)
|
|
USB_Free(__usbfd.buffer);
|
|
__usbfd.buffer= NULL;*/
|
|
__mounted=0;unplug_device=0;
|
|
USBStorage_Close(&__usbfd);
|
|
|
|
|
|
retval=fast_remount();
|
|
usb_timeout=1000*1000;
|
|
if(retval>=0)
|
|
{
|
|
#ifdef MEM_PRINT
|
|
|
|
//s_printf("fast_remount OK\n");
|
|
|
|
#endif
|
|
|
|
// swi_mload_led_off();
|
|
retval=0;unplug_device=0;__mounted=1;
|
|
ehci_int_passive_callback(passive_callback_hand); // interrupt port changes detection
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
}
|
|
else {
|
|
unplug_device=1;
|
|
#ifdef MEM_PRINT
|
|
|
|
s_printf("fast_remount KO ret %i\n", ret);
|
|
|
|
#endif
|
|
__mounted=0;
|
|
retval=1;
|
|
//swi_mload_led_off();
|
|
ehci_msleep(100);
|
|
ehci_int_passive_callback(passive_callback_hand);
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
}
|
|
//if(USBStorage_Try_Device(&ehci->devices[0])==0) {retval=0;unplug_device=0;} else unplug_device=1;
|
|
|
|
}
|
|
}
|
|
ehci_msleep(100);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
int USBStorage_DVD_Test(void)
|
|
{
|
|
|
|
int retval;
|
|
|
|
if(!ums_init_done) return 0;
|
|
unplug_procedure();
|
|
if(unplug_device!=0 || __mounted==0) return 0;
|
|
|
|
// usb_timeout=1000*1000;
|
|
// retval = __usbstorage_clearerrors(&__usbfd, _old_device.lun);
|
|
// if(retval<0) return 0;
|
|
usb_timeout=1000*1000;
|
|
retval = USBStorage_Inquiry(&__usbfd, _old_device.lun);
|
|
if(retval<0) return 0;
|
|
usb_timeout=1000*1000;
|
|
retval = USBStorage_ReadCapacity(&__usbfd, _old_device.lun, &__usbfd.sector_size[_old_device.lun], &__usbfd.n_sector[_old_device.lun]);
|
|
if(retval<0) return 0;
|
|
// sector size check for USB DVD mode (must be 2048 bytes)
|
|
|
|
if(retval>=0 && is_dvd)
|
|
{
|
|
if(__usbfd.sector_size[_old_device.lun]!=2048) return 0;
|
|
}
|
|
|
|
|
|
if(!is_dvd) return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int is_watchdog_read_sector=0;
|
|
|
|
|
|
extern int test_mode;
|
|
|
|
extern int last_sector;
|
|
|
|
s32 USBStorage_Read_Sectors(u32 sector, u32 numSectors, void *buffer)
|
|
{
|
|
s32 retval=0;
|
|
int retry;
|
|
|
|
|
|
if(!is_watchdog_read_sector && is_dvd) last_sector=(int) (sector & 0x7fffffff);//return false;
|
|
|
|
if(test_mode && unplug_device>=2)
|
|
{
|
|
unplug_device=1;
|
|
return false;
|
|
}
|
|
|
|
|
|
for(retry=0;retry<4;retry++)
|
|
{
|
|
//if(!is_watchdog_read_sector && !is_dvd) retry=0; // infinite loop except for watchdog
|
|
|
|
|
|
if(!unplug_procedure())
|
|
{
|
|
retval=0;
|
|
}
|
|
|
|
if(test_mode && unplug_device==3) break;
|
|
|
|
if(retval<0 || __mounted != 1)
|
|
{
|
|
unplug_device=1;
|
|
retval=-1;
|
|
}
|
|
|
|
if(unplug_device!=0 ) { continue;}
|
|
|
|
if(is_dvd)
|
|
usb_timeout=10000*1000;
|
|
else
|
|
usb_timeout=3000*1000;
|
|
|
|
if(retval >= 0)
|
|
{
|
|
|
|
ehci_int_passive_callback(NULL);
|
|
ehci_writel (0, &ehci->regs->intr_enable);
|
|
|
|
retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
|
|
|
|
ehci_int_passive_callback(passive_callback_hand);
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
}
|
|
|
|
|
|
usb_timeout=1000*1000;
|
|
|
|
if(retval<0) unplug_device=1;
|
|
|
|
if(test_mode && unplug_device!=0 ) {retval=-1;/*__mounted=0;*/break;}
|
|
|
|
if(unplug_device!=0 || __mounted != 1) continue;
|
|
|
|
if(retval>=0) break;
|
|
|
|
}
|
|
|
|
if(retval < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
s32 USBStorage_Write_Sectors(u32 sector, u32 numSectors, const void *buffer)
|
|
{
|
|
s32 retval=0;
|
|
|
|
if(is_dvd) return false; // quieto!!!
|
|
|
|
while(1)
|
|
{
|
|
|
|
if(!unplug_procedure())
|
|
{
|
|
retval=0;
|
|
}
|
|
|
|
if(retval<0 || __mounted != 1)
|
|
{
|
|
unplug_device=1;
|
|
retval=-1;
|
|
}
|
|
|
|
if(unplug_device!=0 ) continue;
|
|
|
|
usb_timeout=3000*1000;
|
|
|
|
if(retval >=0)
|
|
{
|
|
ehci_writel (0, &ehci->regs->intr_enable);
|
|
ehci_int_passive_callback(NULL);
|
|
|
|
retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
|
|
|
|
ehci_int_passive_callback(passive_callback_hand);
|
|
ehci_writel (STS_PCD, &ehci->regs->intr_enable);
|
|
}
|
|
|
|
usb_timeout=1000*1000;
|
|
if(retval<0) unplug_device=1;
|
|
|
|
if(unplug_device!=0 ) continue;
|
|
if(retval>=0) break;
|
|
}
|
|
|
|
|
|
if(retval < 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|