@ -113,9 +113,9 @@ static const char hcd_name[] = "isp116x-hcd";
struct isp116x isp116x_dev ;
struct isp116x_platform_data isp116x_board ;
int got_rhsc = 0 ; /* root hub status change */
static int got_rhsc ; /* root hub status change */
struct usb_device * devgone ; /* device which was disconnected */
int rh_devnum = 0 ; /* address of Root Hub endpoint */
static int rh_devnum ; /* address of Root Hub endpoint */
/* ------------------------------------------------------------------------- */
@ -522,11 +522,13 @@ static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
done + = PTD_GET_LEN ( & ptd [ i ] ) ;
cc = PTD_GET_CC ( & ptd [ i ] ) ;
if ( cc = = TD_DATAUNDERRUN ) { /* underrun is no error... */
DBG ( " allowed data underrun " ) ;
cc = TD_CC_NOERROR ;
}
if ( cc ! = TD_CC_NOERROR & & ret = = TD_CC_NOERROR )
/* Data underrun means basically that we had more buffer space than
* the function had data . It is perfectly normal but upper levels have
* to know how much we actually transferred .
*/
if ( cc = = TD_NOTACCESSED | |
( cc ! = TD_CC_NOERROR & & ( ret = = TD_CC_NOERROR | | ret = = TD_DATAUNDERRUN ) ) )
ret = cc ;
}
@ -592,11 +594,19 @@ static int isp116x_interrupt(struct isp116x *isp116x)
return ret ;
}
# define PTD_NUM 64 /* it should be enougth... */
struct ptd ptd [ PTD_NUM ] ;
/* With one PTD we can transfer almost 1K in one go;
* HC does the splitting into endpoint digestible transactions
*/
struct ptd ptd [ 1 ] ;
static inline int max_transfer_len ( struct usb_device * dev , unsigned long pipe )
{
return min ( PTD_NUM * usb_maxpacket ( dev , pipe ) , PTD_NUM * 16 ) ;
unsigned mpck = usb_maxpacket ( dev , pipe ) ;
/* One PTD can transfer 1023 bytes but try to always
* transfer multiples of endpoint buffer size
*/
return 1023 / mpck * mpck ;
}
/* Do an USB transfer
@ -610,13 +620,21 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
int max = usb_maxpacket ( dev , pipe ) ;
int dir_out = usb_pipeout ( pipe ) ;
int speed_low = usb_pipeslow ( pipe ) ;
int i , done , stat , timeout , cc ;
int retries = 10 ;
int i , done = 0 , stat , timeout , cc ;
/* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
int retries = 500 ;
DBG ( " ------------------------------------------------ " ) ;
dump_msg ( dev , pipe , buffer , len , " SUBMIT " ) ;
DBG ( " ------------------------------------------------ " ) ;
if ( len > = 1024 ) {
ERR ( " Too big job " ) ;
dev - > status = USB_ST_CRC_ERR ;
return - 1 ;
}
if ( isp116x - > disabled ) {
ERR ( " EPIPE " ) ;
dev - > status = USB_ST_CRC_ERR ;
@ -653,29 +671,15 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
isp116x_write_reg32 ( isp116x , HCINTSTAT , 0xff ) ;
/* Prepare the PTD data */
done = 0 ;
i = 0 ;
do {
ptd [ i ] . count = PTD_CC_MSK | PTD_ACTIVE_MSK |
PTD_TOGGLE ( usb_gettoggle ( dev , epnum , dir_out ) ) ;
ptd [ i ] . mps = PTD_MPS ( max ) | PTD_SPD ( speed_low ) | PTD_EP ( epnum ) ;
ptd [ i ] . len = PTD_LEN ( max > len - done ? len - done : max ) |
PTD_DIR ( dir ) ;
ptd [ i ] . faddr = PTD_FA ( usb_pipedevice ( pipe ) ) ;
usb_dotoggle ( dev , epnum , dir_out ) ;
done + = PTD_GET_LEN ( & ptd [ i ] ) ;
i + + ;
if ( i > = PTD_NUM ) {
ERR ( " ****** Cannot pack buffer! ****** " ) ;
dev - > status = USB_ST_BUF_ERR ;
return - 1 ;
}
} while ( done < len ) ;
ptd [ i - 1 ] . mps | = PTD_LAST_MSK ;
ptd - > count = PTD_CC_MSK | PTD_ACTIVE_MSK |
PTD_TOGGLE ( usb_gettoggle ( dev , epnum , dir_out ) ) ;
ptd - > mps = PTD_MPS ( max ) | PTD_SPD ( speed_low ) | PTD_EP ( epnum ) | PTD_LAST_MSK ;
ptd - > len = PTD_LEN ( len ) | PTD_DIR ( dir ) ;
ptd - > faddr = PTD_FA ( usb_pipedevice ( pipe ) ) ;
retry_same :
/* Pack data into FIFO ram */
pack_fifo ( isp116x , dev , pipe , ptd , i , buffer , len ) ;
pack_fifo ( isp116x , dev , pipe , ptd , 1 , buffer , len ) ;
# ifdef EXTRA_DELAY
wait_ms ( EXTRA_DELAY ) ;
# endif
@ -738,17 +742,42 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
}
/* Unpack data from FIFO ram */
cc = unpack_fifo ( isp116x , dev , pipe , ptd , i , buffer , len ) ;
cc = unpack_fifo ( isp116x , dev , pipe , ptd , 1 , buffer , len ) ;
i = PTD_GET_COUNT ( ptd ) ;
done + = i ;
buffer + = i ;
len - = i ;
/* Mmm... sometime we get 0x0f as cc which is a non sense!
* Just retry the transfer . . .
/* There was some kind of real problem; Prepare the PTD again
* and retry from the failed transaction on
*/
if ( cc = = 0x0f & & retries - - > 0 ) {
usb_dotoggle ( dev , epnum , dir_out ) ;
goto retry ;
if ( cc & & cc ! = TD_NOTACCESSED & & cc ! = TD_DATAUNDERRUN ) {
if ( retries > = 100 ) {
retries - = 100 ;
/* The chip will have toggled the toggle bit for the failed
* transaction too . We have to toggle it back .
*/
usb_settoggle ( dev , epnum , dir_out , ! PTD_GET_TOGGLE ( ptd ) ) ;
goto retry ;
}
}
/* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
* the transactions from the first on for the whole frame . It may be busy and we retry
* with the same PTD . PTD_ACTIVE ( and not TD_NOTACCESSED ) would mean that some of the
* PTD didn ' t make it because the function was busy or the frame ended before the PTD
* finished . We prepare the rest of the data and try again .
*/
else if ( cc = = TD_NOTACCESSED | | PTD_GET_ACTIVE ( ptd ) | | ( cc ! = TD_DATAUNDERRUN & & PTD_GET_COUNT ( ptd ) < PTD_GET_LEN ( ptd ) ) ) {
if ( retries ) {
- - retries ;
if ( cc = = TD_NOTACCESSED & & PTD_GET_ACTIVE ( ptd ) & & ! PTD_GET_COUNT ( ptd ) ) goto retry_same ;
usb_settoggle ( dev , epnum , dir_out , PTD_GET_TOGGLE ( ptd ) ) ;
goto retry ;
}
}
if ( cc ! = TD_CC_NOERROR ) {
if ( cc ! = TD_CC_NOERROR & & cc ! = TD_DATAUNDERRUN ) {
DBG ( " ****** completition code error %x ****** " , cc ) ;
switch ( cc ) {
case TD_CC_BITSTUFFING :
@ -766,6 +795,7 @@ static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
}
return - cc ;
}
else usb_settoggle ( dev , epnum , dir_out , PTD_GET_TOGGLE ( ptd ) ) ;
dump_msg ( dev , pipe , buffer , len , " SUBMIT(ret) " ) ;
@ -1369,6 +1399,8 @@ int usb_lowlevel_init(void)
DBG ( " " ) ;
got_rhsc = rh_devnum = 0 ;
/* Init device registers addr */
isp116x - > addr_reg = ( u16 * ) ISP116X_HCD_ADDR ;
isp116x - > data_reg = ( u16 * ) ISP116X_HCD_DATA ;