2005-04-17 02:20:36 +04:00
/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $
*
* isar . c ISAR ( Siemens PSB 7110 ) specific routines
*
* Author Karsten Keil ( keil @ isdn4linux . de )
*
* This file is ( c ) under GNU General Public License
*
*/
# include <linux/init.h>
# include "hisax.h"
# include "isar.h"
# include "isdnl1.h"
# include <linux/interrupt.h>
# define DBG_LOADFIRM 0
# define DUMP_MBOXFRAME 2
# define DLE 0x10
# define ETX 0x03
# define FAXMODCNT 13
2005-06-26 01:59:18 +04:00
static const u_char faxmodulation [ ] = { 3 , 24 , 48 , 72 , 73 , 74 , 96 , 97 , 98 , 121 , 122 , 145 , 146 } ;
2005-04-17 02:20:36 +04:00
static u_int modmask = 0x1fff ;
static int frm_extra_delay = 2 ;
static int para_TOA = 6 ;
2005-06-26 01:59:18 +04:00
static const u_char * FC1_CMD [ ] = { " FAE " , " FTS " , " FRS " , " FTM " , " FRM " , " FTH " , " FRH " , " CTRL " } ;
2005-04-17 02:20:36 +04:00
2005-06-26 01:59:18 +04:00
static void isar_setup ( struct IsdnCardState * cs ) ;
2005-04-17 02:20:36 +04:00
static void isar_pump_cmd ( struct BCState * bcs , u_char cmd , u_char para ) ;
static void ll_deliver_faxstat ( struct BCState * bcs , u_char status ) ;
static inline int
waitforHIA ( struct IsdnCardState * cs , int timeout )
{
while ( ( cs - > BC_Read_Reg ( cs , 0 , ISAR_HIA ) & 1 ) & & timeout ) {
udelay ( 1 ) ;
timeout - - ;
}
if ( ! timeout )
printk ( KERN_WARNING " HiSax: ISAR waitforHIA timeout \n " ) ;
return ( timeout ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
sendmsg ( struct IsdnCardState * cs , u_char his , u_char creg , u_char len ,
u_char * msg )
{
int i ;
if ( ! waitforHIA ( cs , 4000 ) )
return ( 0 ) ;
# if DUMP_MBOXFRAME
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " sendmsg(%02x,%02x,%d) " , his , creg , len ) ;
# endif
cs - > BC_Write_Reg ( cs , 0 , ISAR_CTRL_H , creg ) ;
cs - > BC_Write_Reg ( cs , 0 , ISAR_CTRL_L , len ) ;
cs - > BC_Write_Reg ( cs , 0 , ISAR_WADR , 0 ) ;
if ( msg & & len ) {
cs - > BC_Write_Reg ( cs , 1 , ISAR_MBOX , msg [ 0 ] ) ;
for ( i = 1 ; i < len ; i + + )
cs - > BC_Write_Reg ( cs , 2 , ISAR_MBOX , msg [ i ] ) ;
# if DUMP_MBOXFRAME>1
if ( cs - > debug & L1_DEB_HSCX_FIFO ) {
char tmp [ 256 ] , * t ;
i = len ;
while ( i > 0 ) {
t = tmp ;
t + = sprintf ( t , " sendmbox cnt %d " , len ) ;
QuickHex ( t , & msg [ len - i ] , ( i > 64 ) ? 64 : i ) ;
debugl1 ( cs , tmp ) ;
i - = 64 ;
}
}
# endif
}
cs - > BC_Write_Reg ( cs , 1 , ISAR_HIS , his ) ;
waitforHIA ( cs , 10000 ) ;
return ( 1 ) ;
}
/* Call only with IRQ disabled !!! */
2005-06-26 01:59:18 +04:00
static inline void
2005-04-17 02:20:36 +04:00
rcv_mbox ( struct IsdnCardState * cs , struct isar_reg * ireg , u_char * msg )
{
int i ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_RADR , 0 ) ;
if ( msg & & ireg - > clsb ) {
msg [ 0 ] = cs - > BC_Read_Reg ( cs , 1 , ISAR_MBOX ) ;
for ( i = 1 ; i < ireg - > clsb ; i + + )
msg [ i ] = cs - > BC_Read_Reg ( cs , 2 , ISAR_MBOX ) ;
# if DUMP_MBOXFRAME>1
if ( cs - > debug & L1_DEB_HSCX_FIFO ) {
char tmp [ 256 ] , * t ;
i = ireg - > clsb ;
while ( i > 0 ) {
t = tmp ;
t + = sprintf ( t , " rcv_mbox cnt %d " , ireg - > clsb ) ;
QuickHex ( t , & msg [ ireg - > clsb - i ] , ( i > 64 ) ? 64 : i ) ;
debugl1 ( cs , tmp ) ;
i - = 64 ;
}
}
# endif
}
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
}
/* Call only with IRQ disabled !!! */
2005-06-26 01:59:18 +04:00
static inline void
2005-04-17 02:20:36 +04:00
get_irq_infos ( struct IsdnCardState * cs , struct isar_reg * ireg )
{
ireg - > iis = cs - > BC_Read_Reg ( cs , 1 , ISAR_IIS ) ;
ireg - > cmsb = cs - > BC_Read_Reg ( cs , 1 , ISAR_CTRL_H ) ;
ireg - > clsb = cs - > BC_Read_Reg ( cs , 1 , ISAR_CTRL_L ) ;
# if DUMP_MBOXFRAME
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " irq_stat(%02x,%02x,%d) " , ireg - > iis , ireg - > cmsb ,
ireg - > clsb ) ;
# endif
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
waitrecmsg ( struct IsdnCardState * cs , u_char * len ,
u_char * msg , int maxdelay )
{
int timeout = 0 ;
struct isar_reg * ir = cs - > bcs [ 0 ] . hw . isar . reg ;
while ( ( ! ( cs - > BC_Read_Reg ( cs , 0 , ISAR_IRQBIT ) & ISAR_IRQSTA ) ) & &
( timeout + + < maxdelay ) )
udelay ( 1 ) ;
if ( timeout > = maxdelay ) {
printk ( KERN_WARNING " isar recmsg IRQSTA timeout \n " ) ;
return ( 0 ) ;
}
get_irq_infos ( cs , ir ) ;
rcv_mbox ( cs , ir , msg ) ;
* len = ir - > clsb ;
return ( 1 ) ;
}
int
ISARVersion ( struct IsdnCardState * cs , char * s )
{
int ver ;
u_char msg [ ] = ISAR_MSG_HWVER ;
u_char tmp [ 64 ] ;
u_char len ;
u_long flags ;
int debug ;
cs - > cardmsg ( cs , CARD_RESET , NULL ) ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
/* disable ISAR IRQ */
cs - > BC_Write_Reg ( cs , 0 , ISAR_IRQBIT , 0 ) ;
debug = cs - > debug ;
cs - > debug & = ~ ( L1_DEB_HSCX | L1_DEB_HSCX_FIFO ) ;
if ( ! sendmsg ( cs , ISAR_HIS_VNR , 0 , 3 , msg ) ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return ( - 1 ) ;
}
if ( ! waitrecmsg ( cs , & len , tmp , 100000 ) ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return ( - 2 ) ;
}
cs - > debug = debug ;
if ( cs - > bcs [ 0 ] . hw . isar . reg - > iis = = ISAR_IIS_VNR ) {
if ( len = = 1 ) {
ver = tmp [ 0 ] & 0xf ;
printk ( KERN_INFO " %s ISAR version %d \n " , s , ver ) ;
} else
ver = - 3 ;
} else
ver = - 4 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return ( ver ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
isar_load_firmware ( struct IsdnCardState * cs , u_char __user * buf )
{
int ret , size , cnt , debug ;
u_char len , nom , noc ;
u_short sadr , left , * sp ;
u_char __user * p = buf ;
u_char * msg , * tmpmsg , * mp , tmp [ 64 ] ;
u_long flags ;
struct isar_reg * ireg = cs - > bcs [ 0 ] . hw . isar . reg ;
struct { u_short sadr ;
u_short len ;
u_short d_key ;
} blk_head ;
# define BLK_HEAD_SIZE 6
if ( 1 ! = ( ret = ISARVersion ( cs , " Testing " ) ) ) {
printk ( KERN_ERR " isar_load_firmware wrong isar version %d \n " , ret ) ;
return ( 1 ) ;
}
debug = cs - > debug ;
# if DBG_LOADFIRM<2
cs - > debug & = ~ ( L1_DEB_HSCX | L1_DEB_HSCX_FIFO ) ;
# endif
if ( ( ret = copy_from_user ( & size , p , sizeof ( int ) ) ) ) {
printk ( KERN_ERR " isar_load_firmware copy_from_user ret %d \n " , ret ) ;
return ret ;
}
p + = sizeof ( int ) ;
printk ( KERN_DEBUG " isar_load_firmware size: %d \n " , size ) ;
cnt = 0 ;
/* disable ISAR IRQ */
cs - > BC_Write_Reg ( cs , 0 , ISAR_IRQBIT , 0 ) ;
if ( ! ( msg = kmalloc ( 256 , GFP_KERNEL ) ) ) {
printk ( KERN_ERR " isar_load_firmware no buffer \n " ) ;
return ( 1 ) ;
}
if ( ! ( tmpmsg = kmalloc ( 256 , GFP_KERNEL ) ) ) {
printk ( KERN_ERR " isar_load_firmware no tmp buffer \n " ) ;
kfree ( msg ) ;
return ( 1 ) ;
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
/* disable ISAR IRQ */
cs - > BC_Write_Reg ( cs , 0 , ISAR_IRQBIT , 0 ) ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
while ( cnt < size ) {
if ( ( ret = copy_from_user ( & blk_head , p , BLK_HEAD_SIZE ) ) ) {
printk ( KERN_ERR " isar_load_firmware copy_from_user ret %d \n " , ret ) ;
goto reterror ;
}
# ifdef __BIG_ENDIAN
sadr = ( blk_head . sadr & 0xff ) * 256 + blk_head . sadr / 256 ;
blk_head . sadr = sadr ;
sadr = ( blk_head . len & 0xff ) * 256 + blk_head . len / 256 ;
blk_head . len = sadr ;
sadr = ( blk_head . d_key & 0xff ) * 256 + blk_head . d_key / 256 ;
blk_head . d_key = sadr ;
# endif /* __BIG_ENDIAN */
cnt + = BLK_HEAD_SIZE ;
p + = BLK_HEAD_SIZE ;
printk ( KERN_DEBUG " isar firmware block (%#x,%5d,%#x) \n " ,
blk_head . sadr , blk_head . len , blk_head . d_key & 0xff ) ;
sadr = blk_head . sadr ;
left = blk_head . len ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ! sendmsg ( cs , ISAR_HIS_DKEY , blk_head . d_key & 0xff , 0 , NULL ) ) {
printk ( KERN_ERR " isar sendmsg dkey failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ! waitrecmsg ( cs , & len , tmp , 100000 ) ) {
printk ( KERN_ERR " isar waitrecmsg dkey failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ( ireg - > iis ! = ISAR_IIS_DKEY ) | | ireg - > cmsb | | len ) {
printk ( KERN_ERR " isar wrong dkey response (%x,%x,%x) \n " ,
ireg - > iis , ireg - > cmsb , len ) ;
ret = 1 ; goto reterr_unlock ;
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
while ( left > 0 ) {
if ( left > 126 )
noc = 126 ;
else
noc = left ;
nom = 2 * noc ;
mp = msg ;
* mp + + = sadr / 256 ;
* mp + + = sadr % 256 ;
left - = noc ;
* mp + + = noc ;
if ( ( ret = copy_from_user ( tmpmsg , p , nom ) ) ) {
printk ( KERN_ERR " isar_load_firmware copy_from_user ret %d \n " , ret ) ;
goto reterror ;
}
p + = nom ;
cnt + = nom ;
nom + = 3 ;
sp = ( u_short * ) tmpmsg ;
# if DBG_LOADFIRM
printk ( KERN_DEBUG " isar: load %3d words at %04x left %d \n " ,
noc , sadr , left ) ;
# endif
sadr + = noc ;
while ( noc ) {
# ifdef __BIG_ENDIAN
* mp + + = * sp % 256 ;
* mp + + = * sp / 256 ;
# else
* mp + + = * sp / 256 ;
* mp + + = * sp % 256 ;
# endif /* __BIG_ENDIAN */
sp + + ;
noc - - ;
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ! sendmsg ( cs , ISAR_HIS_FIRM , 0 , nom , msg ) ) {
printk ( KERN_ERR " isar sendmsg prog failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ! waitrecmsg ( cs , & len , tmp , 100000 ) ) {
printk ( KERN_ERR " isar waitrecmsg prog failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ( ireg - > iis ! = ISAR_IIS_FIRM ) | | ireg - > cmsb | | len ) {
printk ( KERN_ERR " isar wrong prog response (%x,%x,%x) \n " ,
ireg - > iis , ireg - > cmsb , len ) ;
ret = 1 ; goto reterr_unlock ;
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
printk ( KERN_DEBUG " isar firmware block %5d words loaded \n " ,
blk_head . len ) ;
}
/* 10ms delay */
cnt = 10 ;
while ( cnt - - )
udelay ( 1000 ) ;
msg [ 0 ] = 0xff ;
msg [ 1 ] = 0xfe ;
ireg - > bstat = 0 ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ! sendmsg ( cs , ISAR_HIS_STDSP , 0 , 2 , msg ) ) {
printk ( KERN_ERR " isar sendmsg start dsp failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ! waitrecmsg ( cs , & len , tmp , 100000 ) ) {
printk ( KERN_ERR " isar waitrecmsg start dsp failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
if ( ( ireg - > iis ! = ISAR_IIS_STDSP ) | | ireg - > cmsb | | len ) {
printk ( KERN_ERR " isar wrong start dsp response (%x,%x,%x) \n " ,
ireg - > iis , ireg - > cmsb , len ) ;
ret = 1 ; goto reterr_unlock ;
} else
printk ( KERN_DEBUG " isar start dsp success \n " ) ;
/* NORMAL mode entered */
/* Enable IRQs of ISAR */
cs - > BC_Write_Reg ( cs , 0 , ISAR_IRQBIT , ISAR_IRQSTA ) ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
cnt = 1000 ; /* max 1s */
while ( ( ! ireg - > bstat ) & & cnt ) {
udelay ( 1000 ) ;
cnt - - ;
}
if ( ! cnt ) {
printk ( KERN_ERR " isar no general status event received \n " ) ;
ret = 1 ; goto reterror ;
} else {
printk ( KERN_DEBUG " isar general status event %x \n " ,
ireg - > bstat ) ;
}
/* 10ms delay */
cnt = 10 ;
while ( cnt - - )
udelay ( 1000 ) ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
ireg - > iis = 0 ;
if ( ! sendmsg ( cs , ISAR_HIS_DIAG , ISAR_CTRL_STST , 0 , NULL ) ) {
printk ( KERN_ERR " isar sendmsg self tst failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
cnt = 10000 ; /* max 100 ms */
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
while ( ( ireg - > iis ! = ISAR_IIS_DIAG ) & & cnt ) {
udelay ( 10 ) ;
cnt - - ;
}
udelay ( 1000 ) ;
if ( ! cnt ) {
printk ( KERN_ERR " isar no self tst response \n " ) ;
ret = 1 ; goto reterror ;
}
if ( ( ireg - > cmsb = = ISAR_CTRL_STST ) & & ( ireg - > clsb = = 1 )
& & ( ireg - > par [ 0 ] = = 0 ) ) {
printk ( KERN_DEBUG " isar selftest OK \n " ) ;
} else {
printk ( KERN_DEBUG " isar selftest not OK %x/%x/%x \n " ,
ireg - > cmsb , ireg - > clsb , ireg - > par [ 0 ] ) ;
ret = 1 ; goto reterror ;
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
ireg - > iis = 0 ;
if ( ! sendmsg ( cs , ISAR_HIS_DIAG , ISAR_CTRL_SWVER , 0 , NULL ) ) {
printk ( KERN_ERR " isar RQST SVN failed \n " ) ;
ret = 1 ; goto reterr_unlock ;
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
cnt = 30000 ; /* max 300 ms */
while ( ( ireg - > iis ! = ISAR_IIS_DIAG ) & & cnt ) {
udelay ( 10 ) ;
cnt - - ;
}
udelay ( 1000 ) ;
if ( ! cnt ) {
printk ( KERN_ERR " isar no SVN response \n " ) ;
ret = 1 ; goto reterror ;
} else {
if ( ( ireg - > cmsb = = ISAR_CTRL_SWVER ) & & ( ireg - > clsb = = 1 ) )
printk ( KERN_DEBUG " isar software version %#x \n " ,
ireg - > par [ 0 ] ) ;
else {
printk ( KERN_ERR " isar wrong swver response (%x,%x) cnt(%d) \n " ,
ireg - > cmsb , ireg - > clsb , cnt ) ;
ret = 1 ; goto reterror ;
}
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
cs - > debug = debug ;
isar_setup ( cs ) ;
ret = 0 ;
reterr_unlock :
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
reterror :
cs - > debug = debug ;
if ( ret )
/* disable ISAR IRQ */
cs - > BC_Write_Reg ( cs , 0 , ISAR_IRQBIT , 0 ) ;
kfree ( msg ) ;
kfree ( tmpmsg ) ;
return ( ret ) ;
}
extern void BChannel_bh ( struct BCState * ) ;
# define B_LL_NOCARRIER 8
# define B_LL_CONNECT 9
# define B_LL_OK 10
static void
isar_bh ( struct BCState * bcs )
{
BChannel_bh ( bcs ) ;
if ( test_and_clear_bit ( B_LL_NOCARRIER , & bcs - > event ) )
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_NOCARR ) ;
if ( test_and_clear_bit ( B_LL_CONNECT , & bcs - > event ) )
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_CONNECT ) ;
if ( test_and_clear_bit ( B_LL_OK , & bcs - > event ) )
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_OK ) ;
}
static void
send_DLE_ETX ( struct BCState * bcs )
{
u_char dleetx [ 2 ] = { DLE , ETX } ;
struct sk_buff * skb ;
if ( ( skb = dev_alloc_skb ( 2 ) ) ) {
memcpy ( skb_put ( skb , 2 ) , dleetx , 2 ) ;
skb_queue_tail ( & bcs - > rqueue , skb ) ;
schedule_event ( bcs , B_RCVBUFREADY ) ;
} else {
printk ( KERN_WARNING " HiSax: skb out of memory \n " ) ;
}
}
static inline int
dle_count ( unsigned char * buf , int len )
{
int count = 0 ;
while ( len - - )
if ( * buf + + = = DLE )
count + + ;
return count ;
}
static inline void
insert_dle ( unsigned char * dest , unsigned char * src , int count ) {
/* <DLE> in input stream have to be flagged as <DLE><DLE> */
while ( count - - ) {
* dest + + = * src ;
if ( * src + + = = DLE )
* dest + + = DLE ;
}
}
static void
isar_rcv_frame ( struct IsdnCardState * cs , struct BCState * bcs )
{
u_char * ptr ;
struct sk_buff * skb ;
struct isar_reg * ireg = bcs - > hw . isar . reg ;
if ( ! ireg - > clsb ) {
debugl1 ( cs , " isar zero len frame " ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
return ;
}
switch ( bcs - > mode ) {
case L1_MODE_NULL :
debugl1 ( cs , " isar mode 0 spurious IIS_RDATA %x/%x/%x " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
printk ( KERN_WARNING " isar mode 0 spurious IIS_RDATA %x/%x/%x \n " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
break ;
case L1_MODE_TRANS :
case L1_MODE_V32 :
if ( ( skb = dev_alloc_skb ( ireg - > clsb ) ) ) {
rcv_mbox ( cs , ireg , ( u_char * ) skb_put ( skb , ireg - > clsb ) ) ;
skb_queue_tail ( & bcs - > rqueue , skb ) ;
schedule_event ( bcs , B_RCVBUFREADY ) ;
} else {
printk ( KERN_WARNING " HiSax: skb out of memory \n " ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
}
break ;
case L1_MODE_HDLC :
if ( ( bcs - > hw . isar . rcvidx + ireg - > clsb ) > HSCX_BUFMAX ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: incoming packet too large " ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
bcs - > hw . isar . rcvidx = 0 ;
} else if ( ireg - > cmsb & HDLC_ERROR ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar frame error %x len %d " ,
ireg - > cmsb , ireg - > clsb ) ;
# ifdef ERROR_STATISTIC
if ( ireg - > cmsb & HDLC_ERR_RER )
bcs - > err_inv + + ;
if ( ireg - > cmsb & HDLC_ERR_CER )
bcs - > err_crc + + ;
# endif
bcs - > hw . isar . rcvidx = 0 ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
} else {
if ( ireg - > cmsb & HDLC_FSD )
bcs - > hw . isar . rcvidx = 0 ;
ptr = bcs - > hw . isar . rcvbuf + bcs - > hw . isar . rcvidx ;
bcs - > hw . isar . rcvidx + = ireg - > clsb ;
rcv_mbox ( cs , ireg , ptr ) ;
if ( ireg - > cmsb & HDLC_FED ) {
if ( bcs - > hw . isar . rcvidx < 3 ) { /* last 2 bytes are the FCS */
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar frame to short %d " ,
bcs - > hw . isar . rcvidx ) ;
} else if ( ! ( skb = dev_alloc_skb ( bcs - > hw . isar . rcvidx - 2 ) ) ) {
printk ( KERN_WARNING " ISAR: receive out of memory \n " ) ;
} else {
memcpy ( skb_put ( skb , bcs - > hw . isar . rcvidx - 2 ) ,
bcs - > hw . isar . rcvbuf , bcs - > hw . isar . rcvidx - 2 ) ;
skb_queue_tail ( & bcs - > rqueue , skb ) ;
schedule_event ( bcs , B_RCVBUFREADY ) ;
}
bcs - > hw . isar . rcvidx = 0 ;
}
}
break ;
case L1_MODE_FAX :
if ( bcs - > hw . isar . state ! = STFAX_ACTIV ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: not ACTIV " ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
bcs - > hw . isar . rcvidx = 0 ;
break ;
}
if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FRM ) {
rcv_mbox ( cs , ireg , bcs - > hw . isar . rcvbuf ) ;
bcs - > hw . isar . rcvidx = ireg - > clsb +
dle_count ( bcs - > hw . isar . rcvbuf , ireg - > clsb ) ;
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar_rcv_frame: raw(%d) dle(%d) " ,
ireg - > clsb , bcs - > hw . isar . rcvidx ) ;
if ( ( skb = dev_alloc_skb ( bcs - > hw . isar . rcvidx ) ) ) {
insert_dle ( ( u_char * ) skb_put ( skb , bcs - > hw . isar . rcvidx ) ,
bcs - > hw . isar . rcvbuf , ireg - > clsb ) ;
skb_queue_tail ( & bcs - > rqueue , skb ) ;
schedule_event ( bcs , B_RCVBUFREADY ) ;
if ( ireg - > cmsb & SART_NMD ) { /* ABORT */
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: no more data " ) ;
bcs - > hw . isar . rcvidx = 0 ;
send_DLE_ETX ( bcs ) ;
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) |
ISAR_HIS_PUMPCTRL , PCTRL_CMD_ESC ,
0 , NULL ) ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
schedule_event ( bcs , B_LL_NOCARRIER ) ;
}
} else {
printk ( KERN_WARNING " HiSax: skb out of memory \n " ) ;
}
break ;
}
if ( bcs - > hw . isar . cmd ! = PCTRL_CMD_FRH ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: unknown fax mode %x " ,
bcs - > hw . isar . cmd ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
bcs - > hw . isar . rcvidx = 0 ;
break ;
}
/* PCTRL_CMD_FRH */
if ( ( bcs - > hw . isar . rcvidx + ireg - > clsb ) > HSCX_BUFMAX ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: incoming packet too large " ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
bcs - > hw . isar . rcvidx = 0 ;
} else if ( ireg - > cmsb & HDLC_ERROR ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar frame error %x len %d " ,
ireg - > cmsb , ireg - > clsb ) ;
bcs - > hw . isar . rcvidx = 0 ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
} else {
if ( ireg - > cmsb & HDLC_FSD ) {
bcs - > hw . isar . rcvidx = 0 ;
}
ptr = bcs - > hw . isar . rcvbuf + bcs - > hw . isar . rcvidx ;
bcs - > hw . isar . rcvidx + = ireg - > clsb ;
rcv_mbox ( cs , ireg , ptr ) ;
if ( ireg - > cmsb & HDLC_FED ) {
int len = bcs - > hw . isar . rcvidx +
dle_count ( bcs - > hw . isar . rcvbuf , bcs - > hw . isar . rcvidx ) ;
if ( bcs - > hw . isar . rcvidx < 3 ) { /* last 2 bytes are the FCS */
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar frame to short %d " ,
bcs - > hw . isar . rcvidx ) ;
printk ( KERN_WARNING " ISAR: frame to short %d \n " ,
bcs - > hw . isar . rcvidx ) ;
} else if ( ! ( skb = dev_alloc_skb ( len ) ) ) {
printk ( KERN_WARNING " ISAR: receive out of memory \n " ) ;
} else {
insert_dle ( ( u_char * ) skb_put ( skb , len ) ,
bcs - > hw . isar . rcvbuf ,
bcs - > hw . isar . rcvidx ) ;
skb_queue_tail ( & bcs - > rqueue , skb ) ;
schedule_event ( bcs , B_RCVBUFREADY ) ;
send_DLE_ETX ( bcs ) ;
schedule_event ( bcs , B_LL_OK ) ;
test_and_clear_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ;
}
bcs - > hw . isar . rcvidx = 0 ;
}
}
if ( ireg - > cmsb & SART_NMD ) { /* ABORT */
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_rcv_frame: no more data " ) ;
bcs - > hw . isar . rcvidx = 0 ;
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) |
ISAR_HIS_PUMPCTRL , PCTRL_CMD_ESC , 0 , NULL ) ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
if ( test_and_clear_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ) {
send_DLE_ETX ( bcs ) ;
schedule_event ( bcs , B_LL_NOCARRIER ) ;
}
}
break ;
default :
printk ( KERN_ERR " isar_rcv_frame mode (%x)error \n " , bcs - > mode ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
break ;
}
}
void
isar_fill_fifo ( struct BCState * bcs )
{
struct IsdnCardState * cs = bcs - > cs ;
int count ;
u_char msb ;
u_char * ptr ;
if ( ( cs - > debug & L1_DEB_HSCX ) & & ! ( cs - > debug & L1_DEB_HSCX_FIFO ) )
debugl1 ( cs , " isar_fill_fifo " ) ;
if ( ! bcs - > tx_skb )
return ;
if ( bcs - > tx_skb - > len < = 0 )
return ;
if ( ! ( bcs - > hw . isar . reg - > bstat &
( bcs - > hw . isar . dpath = = 1 ? BSTAT_RDM1 : BSTAT_RDM2 ) ) )
return ;
if ( bcs - > tx_skb - > len > bcs - > hw . isar . mml ) {
msb = 0 ;
count = bcs - > hw . isar . mml ;
} else {
count = bcs - > tx_skb - > len ;
msb = HDLC_FED ;
}
ptr = bcs - > tx_skb - > data ;
if ( ! bcs - > hw . isar . txcnt ) {
msb | = HDLC_FST ;
if ( ( bcs - > mode = = L1_MODE_FAX ) & &
( bcs - > hw . isar . cmd = = PCTRL_CMD_FTH ) ) {
if ( bcs - > tx_skb - > len > 1 ) {
if ( ( ptr [ 0 ] = = 0xff ) & & ( ptr [ 1 ] = = 0x13 ) )
/* last frame */
test_and_set_bit ( BC_FLG_LASTDATA ,
& bcs - > Flag ) ;
}
}
}
skb_pull ( bcs - > tx_skb , count ) ;
bcs - > tx_cnt - = count ;
bcs - > hw . isar . txcnt + = count ;
switch ( bcs - > mode ) {
case L1_MODE_NULL :
printk ( KERN_ERR " isar_fill_fifo wrong mode 0 \n " ) ;
break ;
case L1_MODE_TRANS :
case L1_MODE_V32 :
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) | ISAR_HIS_SDATA ,
0 , count , ptr ) ;
break ;
case L1_MODE_HDLC :
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) | ISAR_HIS_SDATA ,
msb , count , ptr ) ;
break ;
case L1_MODE_FAX :
if ( bcs - > hw . isar . state ! = STFAX_ACTIV ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_fill_fifo: not ACTIV " ) ;
} else if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FTH ) {
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) | ISAR_HIS_SDATA ,
msb , count , ptr ) ;
} else if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FTM ) {
sendmsg ( cs , SET_DPS ( bcs - > hw . isar . dpath ) | ISAR_HIS_SDATA ,
0 , count , ptr ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar_fill_fifo: not FTH/FTM " ) ;
}
break ;
default :
if ( cs - > debug )
debugl1 ( cs , " isar_fill_fifo mode(%x) error " , bcs - > mode ) ;
printk ( KERN_ERR " isar_fill_fifo mode(%x) error \n " , bcs - > mode ) ;
break ;
}
}
2005-06-26 01:59:18 +04:00
static inline
2005-04-17 02:20:36 +04:00
struct BCState * sel_bcs_isar ( struct IsdnCardState * cs , u_char dpath )
{
if ( ( ! dpath ) | | ( dpath = = 3 ) )
return ( NULL ) ;
if ( cs - > bcs [ 0 ] . hw . isar . dpath = = dpath )
return ( & cs - > bcs [ 0 ] ) ;
if ( cs - > bcs [ 1 ] . hw . isar . dpath = = dpath )
return ( & cs - > bcs [ 1 ] ) ;
return ( NULL ) ;
}
2005-06-26 01:59:18 +04:00
static void
2005-04-17 02:20:36 +04:00
send_frames ( struct BCState * bcs )
{
if ( bcs - > tx_skb ) {
if ( bcs - > tx_skb - > len ) {
isar_fill_fifo ( bcs ) ;
return ;
} else {
if ( test_bit ( FLG_LLI_L1WAKEUP , & bcs - > st - > lli . flag ) & &
( PACKET_NOACK ! = bcs - > tx_skb - > pkt_type ) ) {
u_long flags ;
spin_lock_irqsave ( & bcs - > aclock , flags ) ;
bcs - > ackcnt + = bcs - > hw . isar . txcnt ;
spin_unlock_irqrestore ( & bcs - > aclock , flags ) ;
schedule_event ( bcs , B_ACKPENDING ) ;
}
if ( bcs - > mode = = L1_MODE_FAX ) {
if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FTH ) {
if ( test_bit ( BC_FLG_LASTDATA , & bcs - > Flag ) ) {
test_and_set_bit ( BC_FLG_NMD_DATA , & bcs - > Flag ) ;
}
} else if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FTM ) {
if ( test_bit ( BC_FLG_DLEETX , & bcs - > Flag ) ) {
test_and_set_bit ( BC_FLG_LASTDATA , & bcs - > Flag ) ;
test_and_set_bit ( BC_FLG_NMD_DATA , & bcs - > Flag ) ;
}
}
}
dev_kfree_skb_any ( bcs - > tx_skb ) ;
bcs - > hw . isar . txcnt = 0 ;
bcs - > tx_skb = NULL ;
}
}
if ( ( bcs - > tx_skb = skb_dequeue ( & bcs - > squeue ) ) ) {
bcs - > hw . isar . txcnt = 0 ;
test_and_set_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
isar_fill_fifo ( bcs ) ;
} else {
if ( test_and_clear_bit ( BC_FLG_DLEETX , & bcs - > Flag ) ) {
if ( test_and_clear_bit ( BC_FLG_LASTDATA , & bcs - > Flag ) ) {
if ( test_and_clear_bit ( BC_FLG_NMD_DATA , & bcs - > Flag ) ) {
u_char dummy = 0 ;
sendmsg ( bcs - > cs , SET_DPS ( bcs - > hw . isar . dpath ) |
ISAR_HIS_SDATA , 0x01 , 1 , & dummy ) ;
}
test_and_set_bit ( BC_FLG_LL_OK , & bcs - > Flag ) ;
} else {
schedule_event ( bcs , B_LL_CONNECT ) ;
}
}
test_and_clear_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
schedule_event ( bcs , B_XMTBUFREADY ) ;
}
}
2005-06-26 01:59:18 +04:00
static inline void
2005-04-17 02:20:36 +04:00
check_send ( struct IsdnCardState * cs , u_char rdm )
{
struct BCState * bcs ;
if ( rdm & BSTAT_RDM1 ) {
if ( ( bcs = sel_bcs_isar ( cs , 1 ) ) ) {
if ( bcs - > mode ) {
send_frames ( bcs ) ;
}
}
}
if ( rdm & BSTAT_RDM2 ) {
if ( ( bcs = sel_bcs_isar ( cs , 2 ) ) ) {
if ( bcs - > mode ) {
send_frames ( bcs ) ;
}
}
}
}
2005-06-26 01:59:18 +04:00
static const char * dmril [ ] = { " NO SPEED " , " 1200/75 " , " NODEF2 " , " 75/1200 " ,
" NODEF4 " , " 300 " , " 600 " , " 1200 " , " 2400 " ,
" 4800 " , " 7200 " , " 9600nt " , " 9600t " , " 12000 " ,
" 14400 " , " WRONG " } ;
static const char * dmrim [ ] = { " NO MOD " , " NO DEF " , " V32/V32b " , " V22 " , " V21 " ,
" Bell103 " , " V23 " , " Bell202 " , " V17 " , " V29 " ,
" V27ter " } ;
2005-04-17 02:20:36 +04:00
static void
isar_pump_status_rsp ( struct BCState * bcs , struct isar_reg * ireg ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char ril = ireg - > par [ 0 ] ;
u_char rim ;
if ( ! test_and_clear_bit ( ISAR_RATE_REQ , & bcs - > hw . isar . reg - > Flags ) )
return ;
if ( ril > 14 ) {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " wrong pstrsp ril=%d " , ril ) ;
ril = 15 ;
}
switch ( ireg - > par [ 1 ] ) {
case 0 :
rim = 0 ;
break ;
case 0x20 :
rim = 2 ;
break ;
case 0x40 :
rim = 3 ;
break ;
case 0x41 :
rim = 4 ;
break ;
case 0x51 :
rim = 5 ;
break ;
case 0x61 :
rim = 6 ;
break ;
case 0x71 :
rim = 7 ;
break ;
case 0x82 :
rim = 8 ;
break ;
case 0x92 :
rim = 9 ;
break ;
case 0xa2 :
rim = 10 ;
break ;
default :
rim = 1 ;
break ;
}
sprintf ( bcs - > hw . isar . conmsg , " %s %s " , dmril [ ril ] , dmrim [ rim ] ) ;
bcs - > conmsg = bcs - > hw . isar . conmsg ;
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump strsp %s " , bcs - > conmsg ) ;
}
static void
isar_pump_statev_modem ( struct BCState * bcs , u_char devt ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
switch ( devt ) {
case PSEV_10MS_TIMER :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev TIMER " ) ;
break ;
case PSEV_CON_ON :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev CONNECT " ) ;
l1_msg_b ( bcs - > st , PH_ACTIVATE | REQUEST , NULL ) ;
break ;
case PSEV_CON_OFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev NO CONNECT " ) ;
sendmsg ( cs , dps | ISAR_HIS_PSTREQ , 0 , 0 , NULL ) ;
l1_msg_b ( bcs - > st , PH_DEACTIVATE | REQUEST , NULL ) ;
break ;
case PSEV_V24_OFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev V24 OFF " ) ;
break ;
case PSEV_CTS_ON :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev CTS ON " ) ;
break ;
case PSEV_CTS_OFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev CTS OFF " ) ;
break ;
case PSEV_DCD_ON :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev CARRIER ON " ) ;
test_and_set_bit ( ISAR_RATE_REQ , & bcs - > hw . isar . reg - > Flags ) ;
sendmsg ( cs , dps | ISAR_HIS_PSTREQ , 0 , 0 , NULL ) ;
break ;
case PSEV_DCD_OFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev CARRIER OFF " ) ;
break ;
case PSEV_DSR_ON :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev DSR ON " ) ;
break ;
case PSEV_DSR_OFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev DSR_OFF " ) ;
break ;
case PSEV_REM_RET :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev REMOTE RETRAIN " ) ;
break ;
case PSEV_REM_REN :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev REMOTE RENEGOTIATE " ) ;
break ;
case PSEV_GSTN_CLR :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev GSTN CLEAR " , devt ) ;
break ;
default :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " unknown pump stev %x " , devt ) ;
break ;
}
}
static void
ll_deliver_faxstat ( struct BCState * bcs , u_char status )
{
isdn_ctrl ic ;
struct Channel * chanp = ( struct Channel * ) bcs - > st - > lli . userdata ;
if ( bcs - > cs - > debug & L1_DEB_HSCX )
debugl1 ( bcs - > cs , " HL->LL FAXIND %x " , status ) ;
ic . driver = bcs - > cs - > myid ;
ic . command = ISDN_STAT_FAXIND ;
ic . arg = chanp - > chan ;
ic . parm . aux . cmd = status ;
bcs - > cs - > iif . statcallb ( & ic ) ;
}
static void
isar_pump_statev_fax ( struct BCState * bcs , u_char devt ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
u_char p1 ;
switch ( devt ) {
case PSEV_10MS_TIMER :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev TIMER " ) ;
break ;
case PSEV_RSP_READY :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_READY " ) ;
bcs - > hw . isar . state = STFAX_READY ;
l1_msg_b ( bcs - > st , PH_ACTIVATE | REQUEST , NULL ) ;
if ( test_bit ( BC_FLG_ORIG , & bcs - > Flag ) ) {
isar_pump_cmd ( bcs , ISDN_FAX_CLASS1_FRH , 3 ) ;
} else {
isar_pump_cmd ( bcs , ISDN_FAX_CLASS1_FTH , 3 ) ;
}
break ;
case PSEV_LINE_TX_H :
if ( bcs - > hw . isar . state = = STFAX_LINE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev LINE_TX_H " ) ;
bcs - > hw . isar . state = STFAX_CONT ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , PCTRL_CMD_CONT , 0 , NULL ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " pump stev LINE_TX_H wrong st %x " ,
bcs - > hw . isar . state ) ;
}
break ;
case PSEV_LINE_RX_H :
if ( bcs - > hw . isar . state = = STFAX_LINE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev LINE_RX_H " ) ;
bcs - > hw . isar . state = STFAX_CONT ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , PCTRL_CMD_CONT , 0 , NULL ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " pump stev LINE_RX_H wrong st %x " ,
bcs - > hw . isar . state ) ;
}
break ;
case PSEV_LINE_TX_B :
if ( bcs - > hw . isar . state = = STFAX_LINE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev LINE_TX_B " ) ;
bcs - > hw . isar . state = STFAX_CONT ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , PCTRL_CMD_CONT , 0 , NULL ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " pump stev LINE_TX_B wrong st %x " ,
bcs - > hw . isar . state ) ;
}
break ;
case PSEV_LINE_RX_B :
if ( bcs - > hw . isar . state = = STFAX_LINE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev LINE_RX_B " ) ;
bcs - > hw . isar . state = STFAX_CONT ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , PCTRL_CMD_CONT , 0 , NULL ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " pump stev LINE_RX_B wrong st %x " ,
bcs - > hw . isar . state ) ;
}
break ;
case PSEV_RSP_CONN :
if ( bcs - > hw . isar . state = = STFAX_CONT ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_CONN " ) ;
bcs - > hw . isar . state = STFAX_ACTIV ;
test_and_set_bit ( ISAR_RATE_REQ , & bcs - > hw . isar . reg - > Flags ) ;
sendmsg ( cs , dps | ISAR_HIS_PSTREQ , 0 , 0 , NULL ) ;
if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FTH ) {
/* 1s Flags before data */
if ( test_and_set_bit ( BC_FLG_FTI_RUN , & bcs - > Flag ) )
del_timer ( & bcs - > hw . isar . ftimer ) ;
/* 1000 ms */
bcs - > hw . isar . ftimer . expires =
jiffies + ( ( 1000 * HZ ) / 1000 ) ;
test_and_set_bit ( BC_FLG_LL_CONN ,
& bcs - > Flag ) ;
add_timer ( & bcs - > hw . isar . ftimer ) ;
} else {
schedule_event ( bcs , B_LL_CONNECT ) ;
}
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " pump stev RSP_CONN wrong st %x " ,
bcs - > hw . isar . state ) ;
}
break ;
case PSEV_FLAGS_DET :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev FLAGS_DET " ) ;
break ;
case PSEV_RSP_DISC :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_DISC " ) ;
if ( bcs - > hw . isar . state = = STFAX_ESCAPE ) {
p1 = 5 ;
switch ( bcs - > hw . isar . newcmd ) {
case 0 :
bcs - > hw . isar . state = STFAX_READY ;
break ;
case PCTRL_CMD_FTM :
p1 = 2 ;
case PCTRL_CMD_FTH :
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL ,
PCTRL_CMD_SILON , 1 , & p1 ) ;
bcs - > hw . isar . state = STFAX_SILDET ;
break ;
case PCTRL_CMD_FRM :
if ( frm_extra_delay )
mdelay ( frm_extra_delay ) ;
case PCTRL_CMD_FRH :
p1 = bcs - > hw . isar . mod = bcs - > hw . isar . newmod ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . cmd = bcs - > hw . isar . newcmd ;
bcs - > hw . isar . newcmd = 0 ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL ,
bcs - > hw . isar . cmd , 1 , & p1 ) ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . try_mod = 3 ;
break ;
default :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " RSP_DISC unknown newcmd %x " , bcs - > hw . isar . newcmd ) ;
break ;
}
} else if ( bcs - > hw . isar . state = = STFAX_ACTIV ) {
if ( test_and_clear_bit ( BC_FLG_LL_OK , & bcs - > Flag ) ) {
schedule_event ( bcs , B_LL_OK ) ;
} else if ( bcs - > hw . isar . cmd = = PCTRL_CMD_FRM ) {
send_DLE_ETX ( bcs ) ;
schedule_event ( bcs , B_LL_NOCARRIER ) ;
} else {
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_FCERROR ) ;
}
bcs - > hw . isar . state = STFAX_READY ;
} else {
bcs - > hw . isar . state = STFAX_READY ;
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_FCERROR ) ;
}
break ;
case PSEV_RSP_SILDET :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_SILDET " ) ;
if ( bcs - > hw . isar . state = = STFAX_SILDET ) {
p1 = bcs - > hw . isar . mod = bcs - > hw . isar . newmod ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . cmd = bcs - > hw . isar . newcmd ;
bcs - > hw . isar . newcmd = 0 ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL ,
bcs - > hw . isar . cmd , 1 , & p1 ) ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . try_mod = 3 ;
}
break ;
case PSEV_RSP_SILOFF :
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_SILOFF " ) ;
break ;
case PSEV_RSP_FCERR :
if ( bcs - > hw . isar . state = = STFAX_LINE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_FCERR try %d " ,
bcs - > hw . isar . try_mod ) ;
if ( bcs - > hw . isar . try_mod - - ) {
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL ,
bcs - > hw . isar . cmd , 1 ,
& bcs - > hw . isar . mod ) ;
break ;
}
}
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev RSP_FCERR " ) ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , PCTRL_CMD_ESC , 0 , NULL ) ;
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_FCERROR ) ;
break ;
default :
break ;
}
}
static char debbuf [ 128 ] ;
void
isar_int_main ( struct IsdnCardState * cs )
{
struct isar_reg * ireg = cs - > bcs [ 0 ] . hw . isar . reg ;
struct BCState * bcs ;
get_irq_infos ( cs , ireg ) ;
switch ( ireg - > iis & ISAR_IIS_MSCMSD ) {
case ISAR_IIS_RDATA :
if ( ( bcs = sel_bcs_isar ( cs , ireg - > iis > > 6 ) ) ) {
isar_rcv_frame ( cs , bcs ) ;
} else {
debugl1 ( cs , " isar spurious IIS_RDATA %x/%x/%x " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
}
break ;
case ISAR_IIS_GSTEV :
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
ireg - > bstat | = ireg - > cmsb ;
check_send ( cs , ireg - > cmsb ) ;
break ;
case ISAR_IIS_BSTEV :
# ifdef ERROR_STATISTIC
if ( ( bcs = sel_bcs_isar ( cs , ireg - > iis > > 6 ) ) ) {
if ( ireg - > cmsb = = BSTEV_TBO )
bcs - > err_tx + + ;
if ( ireg - > cmsb = = BSTEV_RBO )
bcs - > err_rdo + + ;
}
# endif
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " Buffer STEV dpath%d msb(%x) " ,
ireg - > iis > > 6 , ireg - > cmsb ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
break ;
case ISAR_IIS_PSTEV :
if ( ( bcs = sel_bcs_isar ( cs , ireg - > iis > > 6 ) ) ) {
rcv_mbox ( cs , ireg , ( u_char * ) ireg - > par ) ;
if ( bcs - > mode = = L1_MODE_V32 ) {
isar_pump_statev_modem ( bcs , ireg - > cmsb ) ;
} else if ( bcs - > mode = = L1_MODE_FAX ) {
isar_pump_statev_fax ( bcs , ireg - > cmsb ) ;
} else if ( ireg - > cmsb = = PSEV_10MS_TIMER ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " pump stev TIMER " ) ;
} else {
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " isar IIS_PSTEV pmode %d stat %x " ,
bcs - > mode , ireg - > cmsb ) ;
}
} else {
debugl1 ( cs , " isar spurious IIS_PSTEV %x/%x/%x " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
}
break ;
case ISAR_IIS_PSTRSP :
if ( ( bcs = sel_bcs_isar ( cs , ireg - > iis > > 6 ) ) ) {
rcv_mbox ( cs , ireg , ( u_char * ) ireg - > par ) ;
isar_pump_status_rsp ( bcs , ireg ) ;
} else {
debugl1 ( cs , " isar spurious IIS_PSTRSP %x/%x/%x " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
cs - > BC_Write_Reg ( cs , 1 , ISAR_IIA , 0 ) ;
}
break ;
case ISAR_IIS_DIAG :
case ISAR_IIS_BSTRSP :
case ISAR_IIS_IOM2RSP :
rcv_mbox ( cs , ireg , ( u_char * ) ireg - > par ) ;
if ( ( cs - > debug & ( L1_DEB_HSCX | L1_DEB_HSCX_FIFO ) )
= = L1_DEB_HSCX ) {
u_char * tp = debbuf ;
tp + = sprintf ( debbuf , " msg iis(%x) msb(%x) " ,
ireg - > iis , ireg - > cmsb ) ;
QuickHex ( tp , ( u_char * ) ireg - > par , ireg - > clsb ) ;
debugl1 ( cs , debbuf ) ;
}
break ;
case ISAR_IIS_INVMSG :
rcv_mbox ( cs , ireg , debbuf ) ;
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " invalid msg his:%x " ,
ireg - > cmsb ) ;
break ;
default :
rcv_mbox ( cs , ireg , debbuf ) ;
if ( cs - > debug & L1_DEB_WARN )
debugl1 ( cs , " unhandled msg iis(%x) ctrl(%x/%x) " ,
ireg - > iis , ireg - > cmsb , ireg - > clsb ) ;
break ;
}
}
static void
ftimer_handler ( struct BCState * bcs ) {
if ( bcs - > cs - > debug )
debugl1 ( bcs - > cs , " ftimer flags %04x " ,
bcs - > Flag ) ;
test_and_clear_bit ( BC_FLG_FTI_RUN , & bcs - > Flag ) ;
if ( test_and_clear_bit ( BC_FLG_LL_CONN , & bcs - > Flag ) ) {
schedule_event ( bcs , B_LL_CONNECT ) ;
}
if ( test_and_clear_bit ( BC_FLG_FTI_FTS , & bcs - > Flag ) ) {
schedule_event ( bcs , B_LL_OK ) ;
}
}
static void
setup_pump ( struct BCState * bcs ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
u_char ctrl , param [ 6 ] ;
switch ( bcs - > mode ) {
case L1_MODE_NULL :
case L1_MODE_TRANS :
case L1_MODE_HDLC :
sendmsg ( cs , dps | ISAR_HIS_PUMPCFG , PMOD_BYPASS , 0 , NULL ) ;
break ;
case L1_MODE_V32 :
ctrl = PMOD_DATAMODEM ;
if ( test_bit ( BC_FLG_ORIG , & bcs - > Flag ) ) {
ctrl | = PCTRL_ORIG ;
param [ 5 ] = PV32P6_CTN ;
} else {
param [ 5 ] = PV32P6_ATN ;
}
param [ 0 ] = para_TOA ; /* 6 db */
param [ 1 ] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
PV32P2_V22C | PV32P2_V21 | PV32P2_BEL ;
param [ 2 ] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B ;
param [ 3 ] = PV32P4_UT144 ;
param [ 4 ] = PV32P5_UT144 ;
sendmsg ( cs , dps | ISAR_HIS_PUMPCFG , ctrl , 6 , param ) ;
break ;
case L1_MODE_FAX :
ctrl = PMOD_FAX ;
if ( test_bit ( BC_FLG_ORIG , & bcs - > Flag ) ) {
ctrl | = PCTRL_ORIG ;
param [ 1 ] = PFAXP2_CTN ;
} else {
param [ 1 ] = PFAXP2_ATN ;
}
param [ 0 ] = para_TOA ; /* 6 db */
sendmsg ( cs , dps | ISAR_HIS_PUMPCFG , ctrl , 2 , param ) ;
bcs - > hw . isar . state = STFAX_NULL ;
bcs - > hw . isar . newcmd = 0 ;
bcs - > hw . isar . newmod = 0 ;
test_and_set_bit ( BC_FLG_FTI_RUN , & bcs - > Flag ) ;
break ;
}
udelay ( 1000 ) ;
sendmsg ( cs , dps | ISAR_HIS_PSTREQ , 0 , 0 , NULL ) ;
udelay ( 1000 ) ;
}
static void
setup_sart ( struct BCState * bcs ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
u_char ctrl , param [ 2 ] ;
switch ( bcs - > mode ) {
case L1_MODE_NULL :
sendmsg ( cs , dps | ISAR_HIS_SARTCFG , SMODE_DISABLE , 0 ,
NULL ) ;
break ;
case L1_MODE_TRANS :
sendmsg ( cs , dps | ISAR_HIS_SARTCFG , SMODE_BINARY , 2 ,
" \0 \0 " ) ;
break ;
case L1_MODE_HDLC :
param [ 0 ] = 0 ;
sendmsg ( cs , dps | ISAR_HIS_SARTCFG , SMODE_HDLC , 1 ,
param ) ;
break ;
case L1_MODE_V32 :
ctrl = SMODE_V14 | SCTRL_HDMC_BOTH ;
param [ 0 ] = S_P1_CHS_8 ;
param [ 1 ] = S_P2_BFT_DEF ;
sendmsg ( cs , dps | ISAR_HIS_SARTCFG , ctrl , 2 ,
param ) ;
break ;
case L1_MODE_FAX :
/* SART must not configured with FAX */
break ;
}
udelay ( 1000 ) ;
sendmsg ( cs , dps | ISAR_HIS_BSTREQ , 0 , 0 , NULL ) ;
udelay ( 1000 ) ;
}
static void
setup_iom2 ( struct BCState * bcs ) {
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
u_char cmsb = IOM_CTRL_ENA , msg [ 5 ] = { IOM_P1_TXD , 0 , 0 , 0 , 0 } ;
if ( bcs - > channel )
msg [ 1 ] = msg [ 3 ] = 1 ;
switch ( bcs - > mode ) {
case L1_MODE_NULL :
cmsb = 0 ;
/* dummy slot */
msg [ 1 ] = msg [ 3 ] = bcs - > hw . isar . dpath + 2 ;
break ;
case L1_MODE_TRANS :
case L1_MODE_HDLC :
break ;
case L1_MODE_V32 :
case L1_MODE_FAX :
cmsb | = IOM_CTRL_ALAW | IOM_CTRL_RCV ;
break ;
}
sendmsg ( cs , dps | ISAR_HIS_IOM2CFG , cmsb , 5 , msg ) ;
udelay ( 1000 ) ;
sendmsg ( cs , dps | ISAR_HIS_IOM2REQ , 0 , 0 , NULL ) ;
udelay ( 1000 ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
modeisar ( struct BCState * bcs , int mode , int bc )
{
struct IsdnCardState * cs = bcs - > cs ;
/* Here we are selecting the best datapath for requested mode */
if ( bcs - > mode = = L1_MODE_NULL ) { /* New Setup */
bcs - > channel = bc ;
switch ( mode ) {
case L1_MODE_NULL : /* init */
if ( ! bcs - > hw . isar . dpath )
/* no init for dpath 0 */
return ( 0 ) ;
break ;
case L1_MODE_TRANS :
case L1_MODE_HDLC :
/* best is datapath 2 */
if ( ! test_and_set_bit ( ISAR_DP2_USE ,
& bcs - > hw . isar . reg - > Flags ) )
bcs - > hw . isar . dpath = 2 ;
else if ( ! test_and_set_bit ( ISAR_DP1_USE ,
& bcs - > hw . isar . reg - > Flags ) )
bcs - > hw . isar . dpath = 1 ;
else {
printk ( KERN_WARNING " isar modeisar both pathes in use \n " ) ;
return ( 1 ) ;
}
break ;
case L1_MODE_V32 :
case L1_MODE_FAX :
/* only datapath 1 */
if ( ! test_and_set_bit ( ISAR_DP1_USE ,
& bcs - > hw . isar . reg - > Flags ) )
bcs - > hw . isar . dpath = 1 ;
else {
printk ( KERN_WARNING " isar modeisar analog funktions only with DP1 \n " ) ;
debugl1 ( cs , " isar modeisar analog funktions only with DP1 " ) ;
return ( 1 ) ;
}
break ;
}
}
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar dp%d mode %d->%d ichan %d " ,
bcs - > hw . isar . dpath , bcs - > mode , mode , bc ) ;
bcs - > mode = mode ;
setup_pump ( bcs ) ;
setup_iom2 ( bcs ) ;
setup_sart ( bcs ) ;
if ( bcs - > mode = = L1_MODE_NULL ) {
/* Clear resources */
if ( bcs - > hw . isar . dpath = = 1 )
test_and_clear_bit ( ISAR_DP1_USE , & bcs - > hw . isar . reg - > Flags ) ;
else if ( bcs - > hw . isar . dpath = = 2 )
test_and_clear_bit ( ISAR_DP2_USE , & bcs - > hw . isar . reg - > Flags ) ;
bcs - > hw . isar . dpath = 0 ;
}
return ( 0 ) ;
}
static void
isar_pump_cmd ( struct BCState * bcs , u_char cmd , u_char para )
{
struct IsdnCardState * cs = bcs - > cs ;
u_char dps = SET_DPS ( bcs - > hw . isar . dpath ) ;
u_char ctrl = 0 , nom = 0 , p1 = 0 ;
switch ( cmd ) {
case ISDN_FAX_CLASS1_FTM :
test_and_clear_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ;
if ( bcs - > hw . isar . state = = STFAX_READY ) {
p1 = para ;
ctrl = PCTRL_CMD_FTM ;
nom = 1 ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . cmd = ctrl ;
bcs - > hw . isar . mod = para ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . newcmd = 0 ;
bcs - > hw . isar . try_mod = 3 ;
} else if ( ( bcs - > hw . isar . state = = STFAX_ACTIV ) & &
( bcs - > hw . isar . cmd = = PCTRL_CMD_FTM ) & &
( bcs - > hw . isar . mod = = para ) ) {
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_CONNECT ) ;
} else {
bcs - > hw . isar . newmod = para ;
bcs - > hw . isar . newcmd = PCTRL_CMD_FTM ;
nom = 0 ;
ctrl = PCTRL_CMD_ESC ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
}
break ;
case ISDN_FAX_CLASS1_FTH :
test_and_clear_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ;
if ( bcs - > hw . isar . state = = STFAX_READY ) {
p1 = para ;
ctrl = PCTRL_CMD_FTH ;
nom = 1 ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . cmd = ctrl ;
bcs - > hw . isar . mod = para ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . newcmd = 0 ;
bcs - > hw . isar . try_mod = 3 ;
} else if ( ( bcs - > hw . isar . state = = STFAX_ACTIV ) & &
( bcs - > hw . isar . cmd = = PCTRL_CMD_FTH ) & &
( bcs - > hw . isar . mod = = para ) ) {
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_CONNECT ) ;
} else {
bcs - > hw . isar . newmod = para ;
bcs - > hw . isar . newcmd = PCTRL_CMD_FTH ;
nom = 0 ;
ctrl = PCTRL_CMD_ESC ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
}
break ;
case ISDN_FAX_CLASS1_FRM :
test_and_clear_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ;
if ( bcs - > hw . isar . state = = STFAX_READY ) {
p1 = para ;
ctrl = PCTRL_CMD_FRM ;
nom = 1 ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . cmd = ctrl ;
bcs - > hw . isar . mod = para ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . newcmd = 0 ;
bcs - > hw . isar . try_mod = 3 ;
} else if ( ( bcs - > hw . isar . state = = STFAX_ACTIV ) & &
( bcs - > hw . isar . cmd = = PCTRL_CMD_FRM ) & &
( bcs - > hw . isar . mod = = para ) ) {
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_CONNECT ) ;
} else {
bcs - > hw . isar . newmod = para ;
bcs - > hw . isar . newcmd = PCTRL_CMD_FRM ;
nom = 0 ;
ctrl = PCTRL_CMD_ESC ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
}
break ;
case ISDN_FAX_CLASS1_FRH :
test_and_set_bit ( BC_FLG_FRH_WAIT , & bcs - > Flag ) ;
if ( bcs - > hw . isar . state = = STFAX_READY ) {
p1 = para ;
ctrl = PCTRL_CMD_FRH ;
nom = 1 ;
bcs - > hw . isar . state = STFAX_LINE ;
bcs - > hw . isar . cmd = ctrl ;
bcs - > hw . isar . mod = para ;
bcs - > hw . isar . newmod = 0 ;
bcs - > hw . isar . newcmd = 0 ;
bcs - > hw . isar . try_mod = 3 ;
} else if ( ( bcs - > hw . isar . state = = STFAX_ACTIV ) & &
( bcs - > hw . isar . cmd = = PCTRL_CMD_FRH ) & &
( bcs - > hw . isar . mod = = para ) ) {
ll_deliver_faxstat ( bcs , ISDN_FAX_CLASS1_CONNECT ) ;
} else {
bcs - > hw . isar . newmod = para ;
bcs - > hw . isar . newcmd = PCTRL_CMD_FRH ;
nom = 0 ;
ctrl = PCTRL_CMD_ESC ;
bcs - > hw . isar . state = STFAX_ESCAPE ;
}
break ;
case ISDN_FAXPUMP_HALT :
bcs - > hw . isar . state = STFAX_NULL ;
nom = 0 ;
ctrl = PCTRL_CMD_HALT ;
break ;
}
if ( ctrl )
sendmsg ( cs , dps | ISAR_HIS_PUMPCTRL , ctrl , nom , & p1 ) ;
}
2005-06-26 01:59:18 +04:00
static void
2005-04-17 02:20:36 +04:00
isar_setup ( struct IsdnCardState * cs )
{
u_char msg ;
int i ;
/* Dpath 1, 2 */
msg = 61 ;
for ( i = 0 ; i < 2 ; i + + ) {
/* Buffer Config */
sendmsg ( cs , ( i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1 ) |
ISAR_HIS_P12CFG , 4 , 1 , & msg ) ;
cs - > bcs [ i ] . hw . isar . mml = msg ;
cs - > bcs [ i ] . mode = 0 ;
cs - > bcs [ i ] . hw . isar . dpath = i + 1 ;
modeisar ( & cs - > bcs [ i ] , 0 , 0 ) ;
INIT_WORK ( & cs - > bcs [ i ] . tqueue , ( void * ) ( void * ) isar_bh , & cs - > bcs [ i ] ) ;
}
}
2005-06-26 01:59:18 +04:00
static void
2005-04-17 02:20:36 +04:00
isar_l2l1 ( struct PStack * st , int pr , void * arg )
{
struct BCState * bcs = st - > l1 . bcs ;
struct sk_buff * skb = arg ;
int ret ;
u_long flags ;
switch ( pr ) {
case ( PH_DATA | REQUEST ) :
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
if ( bcs - > tx_skb ) {
skb_queue_tail ( & bcs - > squeue , skb ) ;
} else {
bcs - > tx_skb = skb ;
test_and_set_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
if ( bcs - > cs - > debug & L1_DEB_HSCX )
debugl1 ( bcs - > cs , " DRQ set BC_FLG_BUSY " ) ;
bcs - > hw . isar . txcnt = 0 ;
bcs - > cs - > BC_Send_Data ( bcs ) ;
}
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
break ;
case ( PH_PULL | INDICATION ) :
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
if ( bcs - > tx_skb ) {
printk ( KERN_WARNING " isar_l2l1: this shouldn't happen \n " ) ;
} else {
test_and_set_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
if ( bcs - > cs - > debug & L1_DEB_HSCX )
debugl1 ( bcs - > cs , " PUI set BC_FLG_BUSY " ) ;
bcs - > tx_skb = skb ;
bcs - > hw . isar . txcnt = 0 ;
bcs - > cs - > BC_Send_Data ( bcs ) ;
}
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
break ;
case ( PH_PULL | REQUEST ) :
if ( ! bcs - > tx_skb ) {
test_and_clear_bit ( FLG_L1_PULL_REQ , & st - > l1 . Flags ) ;
st - > l1 . l1l2 ( st , PH_PULL | CONFIRM , NULL ) ;
} else
test_and_set_bit ( FLG_L1_PULL_REQ , & st - > l1 . Flags ) ;
break ;
case ( PH_ACTIVATE | REQUEST ) :
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
test_and_set_bit ( BC_FLG_ACTIV , & bcs - > Flag ) ;
bcs - > hw . isar . conmsg [ 0 ] = 0 ;
if ( test_bit ( FLG_ORIG , & st - > l2 . flag ) )
test_and_set_bit ( BC_FLG_ORIG , & bcs - > Flag ) ;
else
test_and_clear_bit ( BC_FLG_ORIG , & bcs - > Flag ) ;
switch ( st - > l1 . mode ) {
case L1_MODE_TRANS :
case L1_MODE_HDLC :
ret = modeisar ( bcs , st - > l1 . mode , st - > l1 . bc ) ;
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
if ( ret )
l1_msg_b ( st , PH_DEACTIVATE | REQUEST , arg ) ;
else
l1_msg_b ( st , PH_ACTIVATE | REQUEST , arg ) ;
break ;
case L1_MODE_V32 :
case L1_MODE_FAX :
ret = modeisar ( bcs , st - > l1 . mode , st - > l1 . bc ) ;
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
if ( ret )
l1_msg_b ( st , PH_DEACTIVATE | REQUEST , arg ) ;
break ;
default :
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
break ;
}
break ;
case ( PH_DEACTIVATE | REQUEST ) :
l1_msg_b ( st , pr , arg ) ;
break ;
case ( PH_DEACTIVATE | CONFIRM ) :
spin_lock_irqsave ( & bcs - > cs - > lock , flags ) ;
switch ( st - > l1 . mode ) {
case L1_MODE_TRANS :
case L1_MODE_HDLC :
case L1_MODE_V32 :
break ;
case L1_MODE_FAX :
isar_pump_cmd ( bcs , ISDN_FAXPUMP_HALT , 0 ) ;
break ;
}
test_and_clear_bit ( BC_FLG_ACTIV , & bcs - > Flag ) ;
test_and_clear_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
if ( bcs - > cs - > debug & L1_DEB_HSCX )
debugl1 ( bcs - > cs , " PDAC clear BC_FLG_BUSY " ) ;
modeisar ( bcs , 0 , st - > l1 . bc ) ;
spin_unlock_irqrestore ( & bcs - > cs - > lock , flags ) ;
st - > l1 . l1l2 ( st , PH_DEACTIVATE | CONFIRM , NULL ) ;
break ;
}
}
2005-06-26 01:59:18 +04:00
static void
2005-04-17 02:20:36 +04:00
close_isarstate ( struct BCState * bcs )
{
modeisar ( bcs , 0 , bcs - > channel ) ;
if ( test_and_clear_bit ( BC_FLG_INIT , & bcs - > Flag ) ) {
if ( bcs - > hw . isar . rcvbuf ) {
kfree ( bcs - > hw . isar . rcvbuf ) ;
bcs - > hw . isar . rcvbuf = NULL ;
}
skb_queue_purge ( & bcs - > rqueue ) ;
skb_queue_purge ( & bcs - > squeue ) ;
if ( bcs - > tx_skb ) {
dev_kfree_skb_any ( bcs - > tx_skb ) ;
bcs - > tx_skb = NULL ;
test_and_clear_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
if ( bcs - > cs - > debug & L1_DEB_HSCX )
debugl1 ( bcs - > cs , " closeisar clear BC_FLG_BUSY " ) ;
}
}
del_timer ( & bcs - > hw . isar . ftimer ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
open_isarstate ( struct IsdnCardState * cs , struct BCState * bcs )
{
if ( ! test_and_set_bit ( BC_FLG_INIT , & bcs - > Flag ) ) {
if ( ! ( bcs - > hw . isar . rcvbuf = kmalloc ( HSCX_BUFMAX , GFP_ATOMIC ) ) ) {
printk ( KERN_WARNING
" HiSax: No memory for isar.rcvbuf \n " ) ;
return ( 1 ) ;
}
skb_queue_head_init ( & bcs - > rqueue ) ;
skb_queue_head_init ( & bcs - > squeue ) ;
}
bcs - > tx_skb = NULL ;
test_and_clear_bit ( BC_FLG_BUSY , & bcs - > Flag ) ;
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " openisar clear BC_FLG_BUSY " ) ;
bcs - > event = 0 ;
bcs - > hw . isar . rcvidx = 0 ;
bcs - > tx_cnt = 0 ;
return ( 0 ) ;
}
2005-06-26 01:59:18 +04:00
static int
2005-04-17 02:20:36 +04:00
setstack_isar ( struct PStack * st , struct BCState * bcs )
{
bcs - > channel = st - > l1 . bc ;
if ( open_isarstate ( st - > l1 . hardware , bcs ) )
return ( - 1 ) ;
st - > l1 . bcs = bcs ;
st - > l2 . l2l1 = isar_l2l1 ;
setstack_manager ( st ) ;
bcs - > st = st ;
setstack_l1_B ( st ) ;
return ( 0 ) ;
}
int
isar_auxcmd ( struct IsdnCardState * cs , isdn_ctrl * ic ) {
u_long adr ;
int features , i ;
struct BCState * bcs ;
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar_auxcmd cmd/ch %x/%d " , ic - > command , ic - > arg ) ;
switch ( ic - > command ) {
case ( ISDN_CMD_FAXCMD ) :
bcs = cs - > channel [ ic - > arg ] . bcs ;
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar_auxcmd cmd/subcmd %d/%d " ,
ic - > parm . aux . cmd , ic - > parm . aux . subcmd ) ;
switch ( ic - > parm . aux . cmd ) {
case ISDN_FAX_CLASS1_CTRL :
if ( ic - > parm . aux . subcmd = = ETX )
test_and_set_bit ( BC_FLG_DLEETX ,
& bcs - > Flag ) ;
break ;
case ISDN_FAX_CLASS1_FTS :
if ( ic - > parm . aux . subcmd = = AT_QUERY ) {
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_OK ;
cs - > iif . statcallb ( ic ) ;
return ( 0 ) ;
} else if ( ic - > parm . aux . subcmd = = AT_EQ_QUERY ) {
strcpy ( ic - > parm . aux . para , " 0-255 " ) ;
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_QUERY ;
cs - > iif . statcallb ( ic ) ;
return ( 0 ) ;
} else if ( ic - > parm . aux . subcmd = = AT_EQ_VALUE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar_auxcmd %s=%d " ,
FC1_CMD [ ic - > parm . aux . cmd ] , ic - > parm . aux . para [ 0 ] ) ;
if ( bcs - > hw . isar . state = = STFAX_READY ) {
if ( ! ic - > parm . aux . para [ 0 ] ) {
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_OK ;
cs - > iif . statcallb ( ic ) ;
return ( 0 ) ;
}
if ( ! test_and_set_bit ( BC_FLG_FTI_RUN , & bcs - > Flag ) ) {
/* n*10 ms */
bcs - > hw . isar . ftimer . expires =
jiffies + ( ( ic - > parm . aux . para [ 0 ] * 10 * HZ ) / 1000 ) ;
test_and_set_bit ( BC_FLG_FTI_FTS , & bcs - > Flag ) ;
add_timer ( & bcs - > hw . isar . ftimer ) ;
return ( 0 ) ;
} else {
if ( cs - > debug )
debugl1 ( cs , " isar FTS=%d and FTI busy " ,
ic - > parm . aux . para [ 0 ] ) ;
}
} else {
if ( cs - > debug )
debugl1 ( cs , " isar FTS=%d and isar.state not ready(%x) " ,
ic - > parm . aux . para [ 0 ] , bcs - > hw . isar . state ) ;
}
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_ERROR ;
cs - > iif . statcallb ( ic ) ;
}
break ;
case ISDN_FAX_CLASS1_FRM :
case ISDN_FAX_CLASS1_FRH :
case ISDN_FAX_CLASS1_FTM :
case ISDN_FAX_CLASS1_FTH :
if ( ic - > parm . aux . subcmd = = AT_QUERY ) {
sprintf ( ic - > parm . aux . para ,
" %d " , bcs - > hw . isar . mod ) ;
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_QUERY ;
cs - > iif . statcallb ( ic ) ;
return ( 0 ) ;
} else if ( ic - > parm . aux . subcmd = = AT_EQ_QUERY ) {
char * p = ic - > parm . aux . para ;
for ( i = 0 ; i < FAXMODCNT ; i + + )
if ( ( 1 < < i ) & modmask )
p + = sprintf ( p , " %d, " , faxmodulation [ i ] ) ;
p - - ;
* p = 0 ;
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_QUERY ;
cs - > iif . statcallb ( ic ) ;
return ( 0 ) ;
} else if ( ic - > parm . aux . subcmd = = AT_EQ_VALUE ) {
if ( cs - > debug & L1_DEB_HSCX )
debugl1 ( cs , " isar_auxcmd %s=%d " ,
FC1_CMD [ ic - > parm . aux . cmd ] , ic - > parm . aux . para [ 0 ] ) ;
for ( i = 0 ; i < FAXMODCNT ; i + + )
if ( faxmodulation [ i ] = = ic - > parm . aux . para [ 0 ] )
break ;
if ( ( i < FAXMODCNT ) & & ( ( 1 < < i ) & modmask ) & &
test_bit ( BC_FLG_INIT , & bcs - > Flag ) ) {
isar_pump_cmd ( bcs ,
ic - > parm . aux . cmd ,
ic - > parm . aux . para [ 0 ] ) ;
return ( 0 ) ;
}
}
/* wrong modulation or not activ */
/* fall through */
default :
ic - > command = ISDN_STAT_FAXIND ;
ic - > parm . aux . cmd = ISDN_FAX_CLASS1_ERROR ;
cs - > iif . statcallb ( ic ) ;
}
break ;
case ( ISDN_CMD_IOCTL ) :
switch ( ic - > arg ) {
case 9 : /* load firmware */
features = ISDN_FEATURE_L2_MODEM |
ISDN_FEATURE_L2_FAX |
ISDN_FEATURE_L3_FCLASS1 ;
memcpy ( & adr , ic - > parm . num , sizeof ( ulong ) ) ;
if ( isar_load_firmware ( cs , ( u_char __user * ) adr ) )
return ( 1 ) ;
else
ll_run ( cs , features ) ;
break ;
case 20 :
features = * ( unsigned int * ) ic - > parm . num ;
printk ( KERN_DEBUG " HiSax: max modulation old(%04x) new(%04x) \n " ,
modmask , features ) ;
modmask = features ;
break ;
case 21 :
features = * ( unsigned int * ) ic - > parm . num ;
printk ( KERN_DEBUG " HiSax: FRM extra delay old(%d) new(%d) ms \n " ,
frm_extra_delay , features ) ;
if ( features > = 0 )
frm_extra_delay = features ;
break ;
case 22 :
features = * ( unsigned int * ) ic - > parm . num ;
printk ( KERN_DEBUG " HiSax: TOA old(%d) new(%d) db \n " ,
para_TOA , features ) ;
if ( features > = 0 & & features < 32 )
para_TOA = features ;
break ;
default :
printk ( KERN_DEBUG " HiSax: invalid ioctl %d \n " ,
( int ) ic - > arg ) ;
return ( - EINVAL ) ;
}
break ;
default :
return ( - EINVAL ) ;
}
return ( 0 ) ;
}
void __devinit
initisar ( struct IsdnCardState * cs )
{
cs - > bcs [ 0 ] . BC_SetStack = setstack_isar ;
cs - > bcs [ 1 ] . BC_SetStack = setstack_isar ;
cs - > bcs [ 0 ] . BC_Close = close_isarstate ;
cs - > bcs [ 1 ] . BC_Close = close_isarstate ;
cs - > bcs [ 0 ] . hw . isar . ftimer . function = ( void * ) ftimer_handler ;
cs - > bcs [ 0 ] . hw . isar . ftimer . data = ( long ) & cs - > bcs [ 0 ] ;
init_timer ( & cs - > bcs [ 0 ] . hw . isar . ftimer ) ;
cs - > bcs [ 1 ] . hw . isar . ftimer . function = ( void * ) ftimer_handler ;
cs - > bcs [ 1 ] . hw . isar . ftimer . data = ( long ) & cs - > bcs [ 1 ] ;
init_timer ( & cs - > bcs [ 1 ] . hw . isar . ftimer ) ;
}