2006-03-26 13:38:31 +04:00
/*
* Stuff used by all variants of the driver
*
2006-04-11 09:55:14 +04:00
* Copyright ( c ) 2001 by Stefan Eilers ,
* Hansjoerg Lipp < hjlipp @ web . de > ,
* Tilman Schmidt < tilman @ imap . cc > .
2006-03-26 13:38:31 +04:00
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "gigaset.h"
2006-04-11 09:55:04 +04:00
/* == Handling of I4L IO =====================================================*/
2006-03-26 13:38:31 +04:00
/* writebuf_from_LL
* called by LL to transmit data on an open channel
* inserts the buffer data into the send queue and starts the transmission
* Note that this operation must not sleep !
* When the buffer is processed completely , gigaset_skb_sent ( ) should be called .
* parameters :
* driverID driver ID as assigned by LL
* channel channel number
2006-04-11 09:55:00 +04:00
* ack if ! = 0 LL wants to be notified on completion via
* statcallb ( ISDN_STAT_BSENT )
2006-03-26 13:38:31 +04:00
* skb skb containing data to send
* return value :
* number of accepted bytes
* 0 if temporarily unable to accept data ( out of buffer space )
* < 0 on error ( eg . - EINVAL )
*/
2006-04-11 09:55:04 +04:00
static int writebuf_from_LL ( int driverID , int channel , int ack ,
struct sk_buff * skb )
2006-03-26 13:38:31 +04:00
{
struct cardstate * cs ;
struct bc_state * bcs ;
unsigned len ;
unsigned skblen ;
if ( ! ( cs = gigaset_get_cs_by_id ( driverID ) ) ) {
err ( " %s: invalid driver ID (%d) " , __func__ , driverID ) ;
return - ENODEV ;
}
if ( channel < 0 | | channel > = cs - > channels ) {
err ( " %s: invalid channel ID (%d) " , __func__ , channel ) ;
return - ENODEV ;
}
bcs = & cs - > bcs [ channel ] ;
len = skb - > len ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_LLDATA ,
" Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d) " ,
driverID , channel , ack , len ) ;
2006-03-26 13:38:31 +04:00
if ( ! len ) {
if ( ack )
2006-04-11 09:55:04 +04:00
notice ( " %s: not ACKing empty packet " , __func__ ) ;
2006-03-26 13:38:31 +04:00
return 0 ;
}
if ( len > MAX_BUF_SIZE ) {
2006-04-11 09:55:04 +04:00
err ( " %s: packet too large (%d bytes) " , __func__ , len ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
skblen = ack ? len : 0 ;
skb - > head [ 0 ] = skblen & 0xff ;
skb - > head [ 1 ] = skblen > > 8 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_MCMD , " skb: len=%u, skblen=%u: %02x %02x " ,
len , skblen , ( unsigned ) skb - > head [ 0 ] , ( unsigned ) skb - > head [ 1 ] ) ;
2006-03-26 13:38:31 +04:00
/* pass to device-specific module */
2006-04-22 13:35:30 +04:00
return cs - > ops - > send_skb ( bcs , skb ) ;
2006-03-26 13:38:31 +04:00
}
void gigaset_skb_sent ( struct bc_state * bcs , struct sk_buff * skb )
{
unsigned len ;
isdn_ctrl response ;
+ + bcs - > trans_up ;
if ( skb - > len )
2006-04-11 09:55:04 +04:00
dev_warn ( bcs - > cs - > dev , " %s: skb->len==%d \n " ,
__func__ , skb - > len ) ;
2006-03-26 13:38:31 +04:00
len = ( unsigned char ) skb - > head [ 0 ] |
( unsigned ) ( unsigned char ) skb - > head [ 1 ] < < 8 ;
if ( len ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_MCMD , " ACKing to LL (id: %d, ch: %d, sz: %u) " ,
bcs - > cs - > myid , bcs - > channel , len ) ;
2006-03-26 13:38:31 +04:00
response . driver = bcs - > cs - > myid ;
response . command = ISDN_STAT_BSENT ;
response . arg = bcs - > channel ;
response . parm . length = len ;
bcs - > cs - > iif . statcallb ( & response ) ;
}
}
EXPORT_SYMBOL_GPL ( gigaset_skb_sent ) ;
/* This function will be called by LL to send commands
* NOTE : LL ignores the returned value , for commands other than ISDN_CMD_IOCTL ,
* so don ' t put too much effort into it .
*/
static int command_from_LL ( isdn_ctrl * cntrl )
{
struct cardstate * cs = gigaset_get_cs_by_id ( cntrl - > driver ) ;
//isdn_ctrl response;
//unsigned long flags;
struct bc_state * bcs ;
int retval = 0 ;
struct setup_parm * sp ;
2006-04-11 09:55:16 +04:00
unsigned param ;
unsigned long flags ;
2006-03-26 13:38:31 +04:00
gigaset_debugdrivers ( ) ;
2006-04-11 09:55:16 +04:00
if ( ! cs ) {
2006-03-26 13:38:31 +04:00
warn ( " LL tried to access unknown device with nr. %d " ,
cntrl - > driver ) ;
return - ENODEV ;
}
switch ( cntrl - > command ) {
case ISDN_CMD_IOCTL :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_IOCTL (driver: %d, arg: %ld) " ,
cntrl - > driver , cntrl - > arg ) ;
2006-03-26 13:38:31 +04:00
warn ( " ISDN_CMD_IOCTL is not supported. " ) ;
return - EINVAL ;
case ISDN_CMD_DIAL :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY ,
" ISDN_CMD_DIAL (driver: %d, ch: %ld, "
" phone: %s, ownmsn: %s, si1: %d, si2: %d) " ,
cntrl - > driver , cntrl - > arg ,
cntrl - > parm . setup . phone , cntrl - > parm . setup . eazmsn ,
cntrl - > parm . setup . si1 , cntrl - > parm . setup . si2 ) ;
2006-03-26 13:38:31 +04:00
if ( cntrl - > arg > = cs - > channels ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_DIAL: invalid channel (%d) " ,
( int ) cntrl - > arg ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
bcs = cs - > bcs + cntrl - > arg ;
if ( ! gigaset_get_channel ( bcs ) ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_DIAL: channel not free " ) ;
2006-03-26 13:38:31 +04:00
return - EBUSY ;
}
sp = kmalloc ( sizeof * sp , GFP_ATOMIC ) ;
if ( ! sp ) {
gigaset_free_channel ( bcs ) ;
err ( " ISDN_CMD_DIAL: out of memory " ) ;
return - ENOMEM ;
}
* sp = cntrl - > parm . setup ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
param = bcs - > at_state . seq_index ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
if ( ! gigaset_add_event ( cs , & bcs - > at_state , EV_DIAL , sp , param ,
2006-04-11 09:55:04 +04:00
NULL ) ) {
2006-03-26 13:38:31 +04:00
//FIXME what should we do?
kfree ( sp ) ;
gigaset_free_channel ( bcs ) ;
return - ENOMEM ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling DIAL " ) ;
2006-03-26 13:38:31 +04:00
gigaset_schedule_event ( cs ) ;
break ;
case ISDN_CMD_ACCEPTD : //FIXME
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_ACCEPTD " ) ;
2006-03-26 13:38:31 +04:00
if ( cntrl - > arg > = cs - > channels ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_ACCEPTD: invalid channel (%d) " ,
( int ) cntrl - > arg ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
if ( ! gigaset_add_event ( cs , & cs - > bcs [ cntrl - > arg ] . at_state ,
2006-04-11 09:55:04 +04:00
EV_ACCEPT , NULL , 0 , NULL ) ) {
2006-03-26 13:38:31 +04:00
//FIXME what should we do?
return - ENOMEM ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling ACCEPT " ) ;
2006-03-26 13:38:31 +04:00
gigaset_schedule_event ( cs ) ;
break ;
case ISDN_CMD_ACCEPTB :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_ACCEPTB " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_HANGUP :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_HANGUP (ch: %d) " ,
( int ) cntrl - > arg ) ;
2006-03-26 13:38:31 +04:00
if ( cntrl - > arg > = cs - > channels ) {
err ( " ISDN_CMD_HANGUP: invalid channel (%u) " ,
( unsigned ) cntrl - > arg ) ;
return - EINVAL ;
}
if ( ! gigaset_add_event ( cs , & cs - > bcs [ cntrl - > arg ] . at_state ,
2006-04-11 09:55:04 +04:00
EV_HUP , NULL , 0 , NULL ) ) {
2006-03-26 13:38:31 +04:00
//FIXME what should we do?
return - ENOMEM ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling HUP " ) ;
2006-03-26 13:38:31 +04:00
gigaset_schedule_event ( cs ) ;
break ;
2006-04-11 09:55:00 +04:00
case ISDN_CMD_CLREAZ : /* Do not signal incoming signals */ //FIXME
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_CLREAZ " ) ;
2006-03-26 13:38:31 +04:00
break ;
2006-04-11 09:55:00 +04:00
case ISDN_CMD_SETEAZ : /* Signal incoming calls for given MSN */ //FIXME
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY ,
" ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s) " ,
cntrl - > driver , cntrl - > arg , cntrl - > parm . num ) ;
2006-03-26 13:38:31 +04:00
break ;
2006-04-11 09:55:00 +04:00
case ISDN_CMD_SETL2 : /* Set L2 to given protocol */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_SETL2 (ch: %ld, proto: %lx) " ,
cntrl - > arg & 0xff , ( cntrl - > arg > > 8 ) ) ;
2006-03-26 13:38:31 +04:00
if ( ( cntrl - > arg & 0xff ) > = cs - > channels ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_SETL2: invalid channel (%u) " ,
2006-03-26 13:38:31 +04:00
( unsigned ) cntrl - > arg & 0xff ) ;
return - EINVAL ;
}
if ( ! gigaset_add_event ( cs , & cs - > bcs [ cntrl - > arg & 0xff ] . at_state ,
2006-04-11 09:55:04 +04:00
EV_PROTO_L2 , NULL , cntrl - > arg > > 8 ,
NULL ) ) {
2006-03-26 13:38:31 +04:00
//FIXME what should we do?
return - ENOMEM ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " scheduling PROTO_L2 " ) ;
2006-03-26 13:38:31 +04:00
gigaset_schedule_event ( cs ) ;
break ;
2006-04-11 09:55:00 +04:00
case ISDN_CMD_SETL3 : /* Set L3 to given protocol */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_SETL3 (ch: %ld, proto: %lx) " ,
cntrl - > arg & 0xff , ( cntrl - > arg > > 8 ) ) ;
2006-03-26 13:38:31 +04:00
if ( ( cntrl - > arg & 0xff ) > = cs - > channels ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_SETL3: invalid channel (%u) " ,
2006-03-26 13:38:31 +04:00
( unsigned ) cntrl - > arg & 0xff ) ;
return - EINVAL ;
}
if ( cntrl - > arg > > 8 ! = ISDN_PROTO_L3_TRANS ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_SETL3: invalid protocol %lu " ,
cntrl - > arg > > 8 ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
break ;
case ISDN_CMD_PROCEED :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_PROCEED " ) ; //FIXME
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_ALERT :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_ALERT " ) ; //FIXME
2006-03-26 13:38:31 +04:00
if ( cntrl - > arg > = cs - > channels ) {
2006-04-11 09:55:04 +04:00
err ( " ISDN_CMD_ALERT: invalid channel (%d) " ,
( int ) cntrl - > arg ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
//bcs = cs->bcs + cntrl->arg;
//bcs->proto2 = -1;
// FIXME
break ;
case ISDN_CMD_REDIR :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_REDIR " ) ; //FIXME
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_PROT_IO :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_PROT_IO " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_FAXCMD :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_FAXCMD " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_GETL2 :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_GETL2 " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_GETL3 :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_GETL3 " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_GETEAZ :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_GETEAZ " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_SETSIL :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_SETSIL " ) ;
2006-03-26 13:38:31 +04:00
break ;
case ISDN_CMD_GETSIL :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " ISDN_CMD_GETSIL " ) ;
2006-03-26 13:38:31 +04:00
break ;
default :
2006-04-11 09:55:04 +04:00
err ( " unknown command %d from LL " , cntrl - > command ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
return retval ;
}
void gigaset_i4l_cmd ( struct cardstate * cs , int cmd )
{
isdn_ctrl command ;
command . driver = cs - > myid ;
command . command = cmd ;
command . arg = 0 ;
cs - > iif . statcallb ( & command ) ;
}
void gigaset_i4l_channel_cmd ( struct bc_state * bcs , int cmd )
{
isdn_ctrl command ;
command . driver = bcs - > cs - > myid ;
command . command = cmd ;
command . arg = bcs - > channel ;
bcs - > cs - > iif . statcallb ( & command ) ;
}
int gigaset_isdn_setup_dial ( struct at_state_t * at_state , void * data )
{
struct bc_state * bcs = at_state - > bcs ;
unsigned proto ;
const char * bc ;
size_t length [ AT_NUM ] ;
size_t l ;
int i ;
struct setup_parm * sp = data ;
switch ( bcs - > proto2 ) {
case ISDN_PROTO_L2_HDLC :
proto = 1 ; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break ;
case ISDN_PROTO_L2_TRANS :
proto = 2 ; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break ;
default :
2006-04-11 09:55:04 +04:00
dev_err ( bcs - > cs - > dev , " %s: invalid L2 protocol: %u \n " ,
__func__ , bcs - > proto2 ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
switch ( sp - > si1 ) {
case 1 : /* audio */
bc = " 9090A3 " ; /* 3.1 kHz audio, A-law */
break ;
case 7 : /* data */
default : /* hope the app knows what it is doing */
bc = " 8890 " ; /* unrestricted digital information */
}
//FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
length [ AT_DIAL ] = 1 + strlen ( sp - > phone ) + 1 + 1 ;
l = strlen ( sp - > eazmsn ) ;
length [ AT_MSN ] = l ? 6 + l + 1 + 1 : 0 ;
length [ AT_BC ] = 5 + strlen ( bc ) + 1 + 1 ;
length [ AT_PROTO ] = 6 + 1 + 1 + 1 ; /* proto: 1 character */
length [ AT_ISO ] = 6 + 1 + 1 + 1 ; /* channel: 1 character */
length [ AT_TYPE ] = 6 + 1 + 1 + 1 ; /* call type: 1 character */
length [ AT_HLC ] = 0 ;
for ( i = 0 ; i < AT_NUM ; + + i ) {
kfree ( bcs - > commands [ i ] ) ;
bcs - > commands [ i ] = NULL ;
if ( length [ i ] & &
! ( bcs - > commands [ i ] = kmalloc ( length [ i ] , GFP_ATOMIC ) ) ) {
2006-04-11 09:55:04 +04:00
dev_err ( bcs - > cs - > dev , " out of memory \n " ) ;
2006-03-26 13:38:31 +04:00
return - ENOMEM ;
}
}
/* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
if ( sp - > phone [ 0 ] = = ' * ' & & sp - > phone [ 1 ] = = ' * ' ) {
/* internal call: translate ** prefix to CTP value */
snprintf ( bcs - > commands [ AT_DIAL ] , length [ AT_DIAL ] ,
" D%s \r " , sp - > phone + 2 ) ;
strncpy ( bcs - > commands [ AT_TYPE ] , " ^SCTP=0 \r " , length [ AT_TYPE ] ) ;
} else {
snprintf ( bcs - > commands [ AT_DIAL ] , length [ AT_DIAL ] ,
" D%s \r " , sp - > phone ) ;
strncpy ( bcs - > commands [ AT_TYPE ] , " ^SCTP=1 \r " , length [ AT_TYPE ] ) ;
}
if ( bcs - > commands [ AT_MSN ] )
2006-04-11 09:55:00 +04:00
snprintf ( bcs - > commands [ AT_MSN ] , length [ AT_MSN ] ,
" ^SMSN=%s \r " , sp - > eazmsn ) ;
snprintf ( bcs - > commands [ AT_BC ] , length [ AT_BC ] ,
" ^SBC=%s \r " , bc ) ;
snprintf ( bcs - > commands [ AT_PROTO ] , length [ AT_PROTO ] ,
" ^SBPR=%u \r " , proto ) ;
snprintf ( bcs - > commands [ AT_ISO ] , length [ AT_ISO ] ,
" ^SISO=%u \r " , ( unsigned ) bcs - > channel + 1 ) ;
2006-03-26 13:38:31 +04:00
return 0 ;
}
int gigaset_isdn_setup_accept ( struct at_state_t * at_state )
{
unsigned proto ;
size_t length [ AT_NUM ] ;
int i ;
struct bc_state * bcs = at_state - > bcs ;
switch ( bcs - > proto2 ) {
case ISDN_PROTO_L2_HDLC :
proto = 1 ; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break ;
case ISDN_PROTO_L2_TRANS :
proto = 2 ; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break ;
default :
2006-04-11 09:55:04 +04:00
dev_err ( at_state - > cs - > dev , " %s: invalid protocol: %u \n " ,
__func__ , bcs - > proto2 ) ;
2006-03-26 13:38:31 +04:00
return - EINVAL ;
}
length [ AT_DIAL ] = 0 ;
length [ AT_MSN ] = 0 ;
length [ AT_BC ] = 0 ;
length [ AT_PROTO ] = 6 + 1 + 1 + 1 ; /* proto: 1 character */
length [ AT_ISO ] = 6 + 1 + 1 + 1 ; /* channel: 1 character */
length [ AT_TYPE ] = 0 ;
length [ AT_HLC ] = 0 ;
for ( i = 0 ; i < AT_NUM ; + + i ) {
kfree ( bcs - > commands [ i ] ) ;
bcs - > commands [ i ] = NULL ;
if ( length [ i ] & &
! ( bcs - > commands [ i ] = kmalloc ( length [ i ] , GFP_ATOMIC ) ) ) {
2006-04-11 09:55:04 +04:00
dev_err ( at_state - > cs - > dev , " out of memory \n " ) ;
2006-03-26 13:38:31 +04:00
return - ENOMEM ;
}
}
2006-04-11 09:55:00 +04:00
snprintf ( bcs - > commands [ AT_PROTO ] , length [ AT_PROTO ] ,
" ^SBPR=%u \r " , proto ) ;
snprintf ( bcs - > commands [ AT_ISO ] , length [ AT_ISO ] ,
" ^SISO=%u \r " , ( unsigned ) bcs - > channel + 1 ) ;
2006-03-26 13:38:31 +04:00
return 0 ;
}
int gigaset_isdn_icall ( struct at_state_t * at_state )
{
struct cardstate * cs = at_state - > cs ;
struct bc_state * bcs = at_state - > bcs ;
isdn_ctrl response ;
int retval ;
/* fill ICALL structure */
response . parm . setup . si1 = 0 ; /* default: unknown */
response . parm . setup . si2 = 0 ;
response . parm . setup . screen = 0 ; //FIXME how to set these?
response . parm . setup . plan = 0 ;
if ( ! at_state - > str_var [ STR_ZBC ] ) {
/* no BC (internal call): assume speech, A-law */
response . parm . setup . si1 = 1 ;
} else if ( ! strcmp ( at_state - > str_var [ STR_ZBC ] , " 8890 " ) ) {
/* unrestricted digital information */
response . parm . setup . si1 = 7 ;
} else if ( ! strcmp ( at_state - > str_var [ STR_ZBC ] , " 8090A3 " ) ) {
/* speech, A-law */
response . parm . setup . si1 = 1 ;
} else if ( ! strcmp ( at_state - > str_var [ STR_ZBC ] , " 9090A3 " ) ) {
/* 3,1 kHz audio, A-law */
response . parm . setup . si1 = 1 ;
response . parm . setup . si2 = 2 ;
} else {
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " RING ignored - unsupported BC %s \n " ,
2006-03-26 13:38:31 +04:00
at_state - > str_var [ STR_ZBC ] ) ;
return ICALL_IGNORE ;
}
if ( at_state - > str_var [ STR_NMBR ] ) {
strncpy ( response . parm . setup . phone , at_state - > str_var [ STR_NMBR ] ,
sizeof response . parm . setup . phone - 1 ) ;
response . parm . setup . phone [ sizeof response . parm . setup . phone - 1 ] = 0 ;
} else
response . parm . setup . phone [ 0 ] = 0 ;
if ( at_state - > str_var [ STR_ZCPN ] ) {
strncpy ( response . parm . setup . eazmsn , at_state - > str_var [ STR_ZCPN ] ,
sizeof response . parm . setup . eazmsn - 1 ) ;
response . parm . setup . eazmsn [ sizeof response . parm . setup . eazmsn - 1 ] = 0 ;
} else
response . parm . setup . eazmsn [ 0 ] = 0 ;
if ( ! bcs ) {
2006-04-11 09:55:04 +04:00
dev_notice ( cs - > dev , " no channel for incoming call \n " ) ;
2006-03-26 13:38:31 +04:00
response . command = ISDN_STAT_ICALLW ;
response . arg = 0 ; //FIXME
} else {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Sending ICALL " ) ;
2006-03-26 13:38:31 +04:00
response . command = ISDN_STAT_ICALL ;
response . arg = bcs - > channel ; //FIXME
}
response . driver = cs - > myid ;
retval = cs - > iif . statcallb ( & response ) ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Response: %d " , retval ) ;
2006-03-26 13:38:31 +04:00
switch ( retval ) {
case 0 : /* no takers */
return ICALL_IGNORE ;
case 1 : /* alerting */
bcs - > chstate | = CHS_NOTIFY_LL ;
return ICALL_ACCEPT ;
case 2 : /* reject */
return ICALL_REJECT ;
case 3 : /* incomplete */
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" LL requested unsupported feature: Incomplete Number \n " ) ;
2006-03-26 13:38:31 +04:00
return ICALL_IGNORE ;
case 4 : /* proceeding */
/* Gigaset will send ALERTING anyway.
* There doesn ' t seem to be a way to avoid this .
*/
return ICALL_ACCEPT ;
case 5 : /* deflect */
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" LL requested unsupported feature: Call Deflection \n " ) ;
2006-03-26 13:38:31 +04:00
return ICALL_IGNORE ;
default :
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " LL error %d on ICALL \n " , retval ) ;
2006-03-26 13:38:31 +04:00
return ICALL_IGNORE ;
}
}
/* Set Callback function pointer */
int gigaset_register_to_LL ( struct cardstate * cs , const char * isdnid )
{
isdn_if * iif = & cs - > iif ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " Register driver capabilities to LL " ) ;
2006-03-26 13:38:31 +04:00
//iif->id[sizeof(iif->id) - 1]=0;
//strncpy(iif->id, isdnid, sizeof(iif->id) - 1);
if ( snprintf ( iif - > id , sizeof iif - > id , " %s_%u " , isdnid , cs - > minor_index )
> = sizeof iif - > id )
return - ENOMEM ; //FIXME EINVAL/...??
iif - > owner = THIS_MODULE ;
2006-04-11 09:55:00 +04:00
iif - > channels = cs - > channels ;
2006-03-26 13:38:31 +04:00
iif - > maxbufsize = MAX_BUF_SIZE ;
2006-04-11 09:55:00 +04:00
iif - > features = ISDN_FEATURE_L2_TRANS |
2006-03-26 13:38:31 +04:00
ISDN_FEATURE_L2_HDLC |
# ifdef GIG_X75
ISDN_FEATURE_L2_X75I |
# endif
ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_EURO ;
2006-04-11 09:55:04 +04:00
iif - > hl_hdrlen = HW_HDR_LEN ; /* Area for storing ack */
2006-03-26 13:38:31 +04:00
iif - > command = command_from_LL ;
iif - > writebuf_skb = writebuf_from_LL ;
2006-04-11 09:55:04 +04:00
iif - > writecmd = NULL ; /* Don't support isdnctrl */
iif - > readstat = NULL ; /* Don't support isdnctrl */
iif - > rcvcallb_skb = NULL ; /* Will be set by LL */
iif - > statcallb = NULL ; /* Will be set by LL */
2006-03-26 13:38:31 +04:00
if ( ! register_isdn ( iif ) )
return 0 ;
2006-04-11 09:55:04 +04:00
cs - > myid = iif - > channels ; /* Set my device id */
2006-03-26 13:38:31 +04:00
return 1 ;
}