2005-04-17 02:20:36 +04:00
/* $Id: kcapi.c,v 1.1.2.8 2004/03/26 19:57:20 armin Exp $
*
* Kernel CAPI 2.0 Module
*
* Copyright 1999 by Carsten Paeth < calle @ calle . de >
* Copyright 2002 by Kai Germaschewski < kai @ germaschewski . name >
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
*/
2008-04-28 13:14:42 +04:00
# define AVMB1_COMPAT
2005-04-17 02:20:36 +04:00
# include "kcapi.h"
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/skbuff.h>
# include <linux/workqueue.h>
# include <linux/capi.h>
# include <linux/kernelcapi.h>
# include <linux/init.h>
# include <linux/moduleparam.h>
# include <linux/delay.h>
# include <asm/uaccess.h>
# include <linux/isdn/capicmd.h>
# include <linux/isdn/capiutil.h>
2008-04-28 13:14:42 +04:00
# ifdef AVMB1_COMPAT
2005-04-17 02:20:36 +04:00
# include <linux/b1lli.h>
# endif
2006-03-23 14:00:21 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
static char * revision = " $Revision: 1.1.2.8 $ " ;
/* ------------------------------------------------------------- */
static int showcapimsgs = 0 ;
MODULE_DESCRIPTION ( " CAPI4Linux: kernel CAPI layer " ) ;
MODULE_AUTHOR ( " Carsten Paeth " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( showcapimsgs , uint , 0 ) ;
/* ------------------------------------------------------------- */
struct capi_notifier {
struct work_struct work ;
unsigned int cmd ;
u32 controller ;
u16 applid ;
u32 ncci ;
} ;
/* ------------------------------------------------------------- */
static struct capi_version driver_version = { 2 , 0 , 1 , 1 < < 4 } ;
static char driver_serial [ CAPI_SERIAL_LEN ] = " 0004711 " ;
static char capi_manufakturer [ 64 ] = " AVM Berlin " ;
# define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
LIST_HEAD ( capi_drivers ) ;
DEFINE_RWLOCK ( capi_drivers_list_lock ) ;
static DEFINE_RWLOCK ( application_lock ) ;
2006-03-23 14:00:21 +03:00
static DEFINE_MUTEX ( controller_mutex ) ;
2005-04-17 02:20:36 +04:00
struct capi20_appl * capi_applications [ CAPI_MAXAPPL ] ;
struct capi_ctr * capi_cards [ CAPI_MAXCONTR ] ;
static int ncards ;
/* -------- controller ref counting -------------------------------------- */
static inline struct capi_ctr *
capi_ctr_get ( struct capi_ctr * card )
{
if ( ! try_module_get ( card - > owner ) )
return NULL ;
return card ;
}
static inline void
capi_ctr_put ( struct capi_ctr * card )
{
module_put ( card - > owner ) ;
}
/* ------------------------------------------------------------- */
static inline struct capi_ctr * get_capi_ctr_by_nr ( u16 contr )
{
if ( contr - 1 > = CAPI_MAXCONTR )
return NULL ;
return capi_cards [ contr - 1 ] ;
}
static inline struct capi20_appl * get_capi_appl_by_nr ( u16 applid )
{
if ( applid - 1 > = CAPI_MAXAPPL )
return NULL ;
return capi_applications [ applid - 1 ] ;
}
/* -------- util functions ------------------------------------ */
static inline int capi_cmd_valid ( u8 cmd )
{
switch ( cmd ) {
case CAPI_ALERT :
case CAPI_CONNECT :
case CAPI_CONNECT_ACTIVE :
case CAPI_CONNECT_B3_ACTIVE :
case CAPI_CONNECT_B3 :
case CAPI_CONNECT_B3_T90_ACTIVE :
case CAPI_DATA_B3 :
case CAPI_DISCONNECT_B3 :
case CAPI_DISCONNECT :
case CAPI_FACILITY :
case CAPI_INFO :
case CAPI_LISTEN :
case CAPI_MANUFACTURER :
case CAPI_RESET_B3 :
case CAPI_SELECT_B_PROTOCOL :
return 1 ;
}
return 0 ;
}
static inline int capi_subcmd_valid ( u8 subcmd )
{
switch ( subcmd ) {
case CAPI_REQ :
case CAPI_CONF :
case CAPI_IND :
case CAPI_RESP :
return 1 ;
}
return 0 ;
}
/* ------------------------------------------------------------ */
static void register_appl ( struct capi_ctr * card , u16 applid , capi_register_params * rparam )
{
card = capi_ctr_get ( card ) ;
if ( card )
card - > register_appl ( card , applid , rparam ) ;
else
2008-04-28 13:14:40 +04:00
printk ( KERN_WARNING " %s: cannot get card resources \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
static void release_appl ( struct capi_ctr * card , u16 applid )
{
DBG ( " applid %#x " , applid ) ;
card - > release_appl ( card , applid ) ;
capi_ctr_put ( card ) ;
}
/* -------- KCI_CONTRUP --------------------------------------- */
static void notify_up ( u32 contr )
{
struct capi_ctr * card = get_capi_ctr_by_nr ( contr ) ;
struct capi20_appl * ap ;
u16 applid ;
if ( showcapimsgs & 1 ) {
printk ( KERN_DEBUG " kcapi: notify up contr %d \n " , contr ) ;
}
if ( ! card ) {
2008-04-28 13:14:40 +04:00
printk ( KERN_WARNING " %s: invalid contr %d \n " , __func__ , contr ) ;
2005-04-17 02:20:36 +04:00
return ;
}
for ( applid = 1 ; applid < = CAPI_MAXAPPL ; applid + + ) {
ap = get_capi_appl_by_nr ( applid ) ;
if ( ! ap | | ap - > release_in_progress ) continue ;
register_appl ( card , applid , & ap - > rparam ) ;
if ( ap - > callback & & ! ap - > release_in_progress )
ap - > callback ( KCI_CONTRUP , contr , & card - > profile ) ;
}
}
/* -------- KCI_CONTRDOWN ------------------------------------- */
static void notify_down ( u32 contr )
{
struct capi20_appl * ap ;
u16 applid ;
if ( showcapimsgs & 1 ) {
printk ( KERN_DEBUG " kcapi: notify down contr %d \n " , contr ) ;
}
for ( applid = 1 ; applid < = CAPI_MAXAPPL ; applid + + ) {
ap = get_capi_appl_by_nr ( applid ) ;
if ( ap & & ap - > callback & & ! ap - > release_in_progress )
ap - > callback ( KCI_CONTRDOWN , contr , NULL ) ;
}
}
2006-11-22 17:57:56 +03:00
static void notify_handler ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:57:56 +03:00
struct capi_notifier * np =
container_of ( work , struct capi_notifier , work ) ;
2005-04-17 02:20:36 +04:00
switch ( np - > cmd ) {
case KCI_CONTRUP :
notify_up ( np - > controller ) ;
break ;
case KCI_CONTRDOWN :
notify_down ( np - > controller ) ;
break ;
}
kfree ( np ) ;
}
/*
* The notifier will result in adding / deleteing of devices . Devices can
* only removed in user process , not in bh .
*/
static int notify_push ( unsigned int cmd , u32 controller , u16 applid , u32 ncci )
{
struct capi_notifier * np = kmalloc ( sizeof ( * np ) , GFP_ATOMIC ) ;
if ( ! np )
return - ENOMEM ;
2006-11-22 17:57:56 +03:00
INIT_WORK ( & np - > work , notify_handler ) ;
2005-04-17 02:20:36 +04:00
np - > cmd = cmd ;
np - > controller = controller ;
np - > applid = applid ;
np - > ncci = ncci ;
schedule_work ( & np - > work ) ;
return 0 ;
}
/* -------- Receiver ------------------------------------------ */
2006-11-22 17:57:56 +03:00
static void recv_handler ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
struct sk_buff * skb ;
2006-11-22 17:57:56 +03:00
struct capi20_appl * ap =
container_of ( work , struct capi20_appl , recv_work ) ;
2005-04-17 02:20:36 +04:00
if ( ( ! ap ) | | ( ap - > release_in_progress ) )
return ;
2007-07-17 15:04:16 +04:00
mutex_lock ( & ap - > recv_mtx ) ;
2005-04-17 02:20:36 +04:00
while ( ( skb = skb_dequeue ( & ap - > recv_queue ) ) ) {
if ( CAPIMSG_CMD ( skb - > data ) = = CAPI_DATA_B3_IND )
ap - > nrecvdatapkt + + ;
else
ap - > nrecvctlpkt + + ;
ap - > recv_message ( ap , skb ) ;
}
2007-07-17 15:04:16 +04:00
mutex_unlock ( & ap - > recv_mtx ) ;
2005-04-17 02:20:36 +04:00
}
void capi_ctr_handle_message ( struct capi_ctr * card , u16 appl , struct sk_buff * skb )
{
struct capi20_appl * ap ;
int showctl = 0 ;
u8 cmd , subcmd ;
unsigned long flags ;
2007-03-01 07:13:50 +03:00
_cdebbuf * cdb ;
2005-04-17 02:20:36 +04:00
if ( card - > cardstate ! = CARD_RUNNING ) {
2007-03-01 07:13:50 +03:00
cdb = capi_message2str ( skb - > data ) ;
if ( cdb ) {
printk ( KERN_INFO " kcapi: controller [%03d] not active, got: %s " ,
card - > cnr , cdb - > buf ) ;
cdebbuf_free ( cdb ) ;
} else
printk ( KERN_INFO " kcapi: controller [%03d] not active, cannot trace \n " ,
card - > cnr ) ;
2005-04-17 02:20:36 +04:00
goto error ;
}
cmd = CAPIMSG_COMMAND ( skb - > data ) ;
subcmd = CAPIMSG_SUBCOMMAND ( skb - > data ) ;
if ( cmd = = CAPI_DATA_B3 & & subcmd = = CAPI_IND ) {
card - > nrecvdatapkt + + ;
if ( card - > traceflag > 2 ) showctl | = 2 ;
} else {
card - > nrecvctlpkt + + ;
if ( card - > traceflag ) showctl | = 2 ;
}
showctl | = ( card - > traceflag & 1 ) ;
if ( showctl & 2 ) {
if ( showctl & 1 ) {
2007-03-01 07:13:50 +03:00
printk ( KERN_DEBUG " kcapi: got [%03d] id#%d %s len=%u \n " ,
card - > cnr , CAPIMSG_APPID ( skb - > data ) ,
2005-04-17 02:20:36 +04:00
capi_cmd2str ( cmd , subcmd ) ,
CAPIMSG_LEN ( skb - > data ) ) ;
} else {
2007-03-01 07:13:50 +03:00
cdb = capi_message2str ( skb - > data ) ;
if ( cdb ) {
printk ( KERN_DEBUG " kcapi: got [%03d] %s \n " ,
card - > cnr , cdb - > buf ) ;
cdebbuf_free ( cdb ) ;
} else
printk ( KERN_DEBUG " kcapi: got [%03d] id#%d %s len=%u, cannot trace \n " ,
card - > cnr , CAPIMSG_APPID ( skb - > data ) ,
capi_cmd2str ( cmd , subcmd ) ,
CAPIMSG_LEN ( skb - > data ) ) ;
2005-04-17 02:20:36 +04:00
}
}
read_lock_irqsave ( & application_lock , flags ) ;
ap = get_capi_appl_by_nr ( CAPIMSG_APPID ( skb - > data ) ) ;
if ( ( ! ap ) | | ( ap - > release_in_progress ) ) {
read_unlock_irqrestore ( & application_lock , flags ) ;
2007-03-01 07:13:50 +03:00
cdb = capi_message2str ( skb - > data ) ;
if ( cdb ) {
printk ( KERN_ERR " kcapi: handle_message: applid %d state released (%s) \n " ,
CAPIMSG_APPID ( skb - > data ) , cdb - > buf ) ;
cdebbuf_free ( cdb ) ;
} else
printk ( KERN_ERR " kcapi: handle_message: applid %d state released (%s) cannot trace \n " ,
CAPIMSG_APPID ( skb - > data ) ,
capi_cmd2str ( cmd , subcmd ) ) ;
2005-04-17 02:20:36 +04:00
goto error ;
}
skb_queue_tail ( & ap - > recv_queue , skb ) ;
schedule_work ( & ap - > recv_work ) ;
read_unlock_irqrestore ( & application_lock , flags ) ;
return ;
error :
kfree_skb ( skb ) ;
}
EXPORT_SYMBOL ( capi_ctr_handle_message ) ;
void capi_ctr_ready ( struct capi_ctr * card )
{
card - > cardstate = CARD_RUNNING ;
2007-03-01 07:13:50 +03:00
printk ( KERN_NOTICE " kcapi: card [%03d] \" %s \" ready. \n " ,
2005-04-17 02:20:36 +04:00
card - > cnr , card - > name ) ;
notify_push ( KCI_CONTRUP , card - > cnr , 0 , 0 ) ;
}
EXPORT_SYMBOL ( capi_ctr_ready ) ;
void capi_ctr_reseted ( struct capi_ctr * card )
{
u16 appl ;
DBG ( " " ) ;
if ( card - > cardstate = = CARD_DETECTED )
return ;
card - > cardstate = CARD_DETECTED ;
memset ( card - > manu , 0 , sizeof ( card - > manu ) ) ;
memset ( & card - > version , 0 , sizeof ( card - > version ) ) ;
memset ( & card - > profile , 0 , sizeof ( card - > profile ) ) ;
memset ( card - > serial , 0 , sizeof ( card - > serial ) ) ;
for ( appl = 1 ; appl < = CAPI_MAXAPPL ; appl + + ) {
struct capi20_appl * ap = get_capi_appl_by_nr ( appl ) ;
if ( ! ap | | ap - > release_in_progress )
continue ;
capi_ctr_put ( card ) ;
}
2007-03-01 07:13:50 +03:00
printk ( KERN_NOTICE " kcapi: card [%03d] down. \n " , card - > cnr ) ;
2005-04-17 02:20:36 +04:00
notify_push ( KCI_CONTRDOWN , card - > cnr , 0 , 0 ) ;
}
EXPORT_SYMBOL ( capi_ctr_reseted ) ;
void capi_ctr_suspend_output ( struct capi_ctr * card )
{
if ( ! card - > blocked ) {
2007-03-01 07:13:50 +03:00
printk ( KERN_DEBUG " kcapi: card [%03d] suspend \n " , card - > cnr ) ;
2005-04-17 02:20:36 +04:00
card - > blocked = 1 ;
}
}
EXPORT_SYMBOL ( capi_ctr_suspend_output ) ;
void capi_ctr_resume_output ( struct capi_ctr * card )
{
if ( card - > blocked ) {
2007-03-01 07:13:50 +03:00
printk ( KERN_DEBUG " kcapi: card [%03d] resume \n " , card - > cnr ) ;
2005-04-17 02:20:36 +04:00
card - > blocked = 0 ;
}
}
EXPORT_SYMBOL ( capi_ctr_resume_output ) ;
/* ------------------------------------------------------------- */
int
attach_capi_ctr ( struct capi_ctr * card )
{
int i ;
2006-03-23 14:00:21 +03:00
mutex_lock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CAPI_MAXCONTR ; i + + ) {
if ( capi_cards [ i ] = = NULL )
break ;
}
if ( i = = CAPI_MAXCONTR ) {
2006-03-23 14:00:21 +03:00
mutex_unlock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " kcapi: out of controller slots \n " ) ;
return - EBUSY ;
}
capi_cards [ i ] = card ;
2006-03-23 14:00:21 +03:00
mutex_unlock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
card - > nrecvctlpkt = 0 ;
card - > nrecvdatapkt = 0 ;
card - > nsentctlpkt = 0 ;
card - > nsentdatapkt = 0 ;
card - > cnr = i + 1 ;
card - > cardstate = CARD_DETECTED ;
card - > blocked = 0 ;
card - > traceflag = showcapimsgs ;
sprintf ( card - > procfn , " capi/controllers/%d " , card - > cnr ) ;
card - > procent = create_proc_entry ( card - > procfn , 0 , NULL ) ;
if ( card - > procent ) {
card - > procent - > read_proc =
( int ( * ) ( char * , char * * , off_t , int , int * , void * ) )
card - > ctr_read_proc ;
card - > procent - > data = card ;
}
ncards + + ;
2007-03-01 07:13:50 +03:00
printk ( KERN_NOTICE " kcapi: Controller [%03d]: %s attached \n " ,
2005-04-17 02:20:36 +04:00
card - > cnr , card - > name ) ;
return 0 ;
}
EXPORT_SYMBOL ( attach_capi_ctr ) ;
int detach_capi_ctr ( struct capi_ctr * card )
{
if ( card - > cardstate ! = CARD_DETECTED )
capi_ctr_reseted ( card ) ;
ncards - - ;
if ( card - > procent ) {
remove_proc_entry ( card - > procfn , NULL ) ;
card - > procent = NULL ;
}
capi_cards [ card - > cnr - 1 ] = NULL ;
2007-03-01 07:13:50 +03:00
printk ( KERN_NOTICE " kcapi: Controller [%03d]: %s unregistered \n " ,
2005-04-17 02:20:36 +04:00
card - > cnr , card - > name ) ;
return 0 ;
}
EXPORT_SYMBOL ( detach_capi_ctr ) ;
void register_capi_driver ( struct capi_driver * driver )
{
unsigned long flags ;
write_lock_irqsave ( & capi_drivers_list_lock , flags ) ;
list_add_tail ( & driver - > list , & capi_drivers ) ;
write_unlock_irqrestore ( & capi_drivers_list_lock , flags ) ;
}
EXPORT_SYMBOL ( register_capi_driver ) ;
void unregister_capi_driver ( struct capi_driver * driver )
{
unsigned long flags ;
write_lock_irqsave ( & capi_drivers_list_lock , flags ) ;
list_del ( & driver - > list ) ;
write_unlock_irqrestore ( & capi_drivers_list_lock , flags ) ;
}
EXPORT_SYMBOL ( unregister_capi_driver ) ;
/* ------------------------------------------------------------- */
/* -------- CAPI2.0 Interface ---------------------------------- */
/* ------------------------------------------------------------- */
u16 capi20_isinstalled ( void )
{
int i ;
for ( i = 0 ; i < CAPI_MAXCONTR ; i + + ) {
if ( capi_cards [ i ] & & capi_cards [ i ] - > cardstate = = CARD_RUNNING )
return CAPI_NOERROR ;
}
return CAPI_REGNOTINSTALLED ;
}
EXPORT_SYMBOL ( capi20_isinstalled ) ;
u16 capi20_register ( struct capi20_appl * ap )
{
int i ;
u16 applid ;
unsigned long flags ;
DBG ( " " ) ;
if ( ap - > rparam . datablklen < 128 )
return CAPI_LOGBLKSIZETOSMALL ;
write_lock_irqsave ( & application_lock , flags ) ;
for ( applid = 1 ; applid < = CAPI_MAXAPPL ; applid + + ) {
if ( capi_applications [ applid - 1 ] = = NULL )
break ;
}
if ( applid > CAPI_MAXAPPL ) {
write_unlock_irqrestore ( & application_lock , flags ) ;
return CAPI_TOOMANYAPPLS ;
}
ap - > applid = applid ;
capi_applications [ applid - 1 ] = ap ;
ap - > nrecvctlpkt = 0 ;
ap - > nrecvdatapkt = 0 ;
ap - > nsentctlpkt = 0 ;
ap - > nsentdatapkt = 0 ;
ap - > callback = NULL ;
2007-07-17 15:04:16 +04:00
mutex_init ( & ap - > recv_mtx ) ;
2005-04-17 02:20:36 +04:00
skb_queue_head_init ( & ap - > recv_queue ) ;
2006-11-22 17:57:56 +03:00
INIT_WORK ( & ap - > recv_work , recv_handler ) ;
2005-04-17 02:20:36 +04:00
ap - > release_in_progress = 0 ;
write_unlock_irqrestore ( & application_lock , flags ) ;
2006-03-23 14:00:21 +03:00
mutex_lock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CAPI_MAXCONTR ; i + + ) {
if ( ! capi_cards [ i ] | | capi_cards [ i ] - > cardstate ! = CARD_RUNNING )
continue ;
register_appl ( capi_cards [ i ] , applid , & ap - > rparam ) ;
}
2006-03-23 14:00:21 +03:00
mutex_unlock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( showcapimsgs & 1 ) {
printk ( KERN_DEBUG " kcapi: appl %d up \n " , applid ) ;
}
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_register ) ;
u16 capi20_release ( struct capi20_appl * ap )
{
int i ;
unsigned long flags ;
DBG ( " applid %#x " , ap - > applid ) ;
write_lock_irqsave ( & application_lock , flags ) ;
ap - > release_in_progress = 1 ;
capi_applications [ ap - > applid - 1 ] = NULL ;
write_unlock_irqrestore ( & application_lock , flags ) ;
2006-03-23 14:00:21 +03:00
mutex_lock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CAPI_MAXCONTR ; i + + ) {
if ( ! capi_cards [ i ] | | capi_cards [ i ] - > cardstate ! = CARD_RUNNING )
continue ;
release_appl ( capi_cards [ i ] , ap - > applid ) ;
}
2006-03-23 14:00:21 +03:00
mutex_unlock ( & controller_mutex ) ;
2005-04-17 02:20:36 +04:00
flush_scheduled_work ( ) ;
skb_queue_purge ( & ap - > recv_queue ) ;
if ( showcapimsgs & 1 ) {
printk ( KERN_DEBUG " kcapi: appl %d down \n " , ap - > applid ) ;
}
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_release ) ;
u16 capi20_put_message ( struct capi20_appl * ap , struct sk_buff * skb )
{
struct capi_ctr * card ;
int showctl = 0 ;
u8 cmd , subcmd ;
DBG ( " applid %#x " , ap - > applid ) ;
if ( ncards = = 0 )
return CAPI_REGNOTINSTALLED ;
if ( ( ap - > applid = = 0 ) | | ap - > release_in_progress )
return CAPI_ILLAPPNR ;
if ( skb - > len < 12
| | ! capi_cmd_valid ( CAPIMSG_COMMAND ( skb - > data ) )
| | ! capi_subcmd_valid ( CAPIMSG_SUBCOMMAND ( skb - > data ) ) )
return CAPI_ILLCMDORSUBCMDORMSGTOSMALL ;
card = get_capi_ctr_by_nr ( CAPIMSG_CONTROLLER ( skb - > data ) ) ;
if ( ! card | | card - > cardstate ! = CARD_RUNNING ) {
card = get_capi_ctr_by_nr ( 1 ) ; // XXX why?
if ( ! card | | card - > cardstate ! = CARD_RUNNING )
return CAPI_REGNOTINSTALLED ;
}
if ( card - > blocked )
return CAPI_SENDQUEUEFULL ;
cmd = CAPIMSG_COMMAND ( skb - > data ) ;
subcmd = CAPIMSG_SUBCOMMAND ( skb - > data ) ;
if ( cmd = = CAPI_DATA_B3 & & subcmd = = CAPI_REQ ) {
card - > nsentdatapkt + + ;
ap - > nsentdatapkt + + ;
if ( card - > traceflag > 2 ) showctl | = 2 ;
} else {
card - > nsentctlpkt + + ;
ap - > nsentctlpkt + + ;
if ( card - > traceflag ) showctl | = 2 ;
}
showctl | = ( card - > traceflag & 1 ) ;
if ( showctl & 2 ) {
if ( showctl & 1 ) {
2007-03-01 07:13:50 +03:00
printk ( KERN_DEBUG " kcapi: put [%03d] id#%d %s len=%u \n " ,
2005-04-17 02:20:36 +04:00
CAPIMSG_CONTROLLER ( skb - > data ) ,
CAPIMSG_APPID ( skb - > data ) ,
capi_cmd2str ( cmd , subcmd ) ,
CAPIMSG_LEN ( skb - > data ) ) ;
} else {
2007-03-01 07:13:50 +03:00
_cdebbuf * cdb = capi_message2str ( skb - > data ) ;
if ( cdb ) {
printk ( KERN_DEBUG " kcapi: put [%03d] %s \n " ,
CAPIMSG_CONTROLLER ( skb - > data ) ,
cdb - > buf ) ;
cdebbuf_free ( cdb ) ;
} else
printk ( KERN_DEBUG " kcapi: put [%03d] id#%d %s len=%u cannot trace \n " ,
CAPIMSG_CONTROLLER ( skb - > data ) ,
CAPIMSG_APPID ( skb - > data ) ,
capi_cmd2str ( cmd , subcmd ) ,
CAPIMSG_LEN ( skb - > data ) ) ;
2005-04-17 02:20:36 +04:00
}
}
return card - > send_message ( card , skb ) ;
}
EXPORT_SYMBOL ( capi20_put_message ) ;
u16 capi20_get_manufacturer ( u32 contr , u8 * buf )
{
struct capi_ctr * card ;
if ( contr = = 0 ) {
strlcpy ( buf , capi_manufakturer , CAPI_MANUFACTURER_LEN ) ;
return CAPI_NOERROR ;
}
card = get_capi_ctr_by_nr ( contr ) ;
if ( ! card | | card - > cardstate ! = CARD_RUNNING )
return CAPI_REGNOTINSTALLED ;
strlcpy ( buf , card - > manu , CAPI_MANUFACTURER_LEN ) ;
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_get_manufacturer ) ;
u16 capi20_get_version ( u32 contr , struct capi_version * verp )
{
struct capi_ctr * card ;
if ( contr = = 0 ) {
* verp = driver_version ;
return CAPI_NOERROR ;
}
card = get_capi_ctr_by_nr ( contr ) ;
if ( ! card | | card - > cardstate ! = CARD_RUNNING )
return CAPI_REGNOTINSTALLED ;
memcpy ( ( void * ) verp , & card - > version , sizeof ( capi_version ) ) ;
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_get_version ) ;
u16 capi20_get_serial ( u32 contr , u8 * serial )
{
struct capi_ctr * card ;
if ( contr = = 0 ) {
strlcpy ( serial , driver_serial , CAPI_SERIAL_LEN ) ;
return CAPI_NOERROR ;
}
card = get_capi_ctr_by_nr ( contr ) ;
if ( ! card | | card - > cardstate ! = CARD_RUNNING )
return CAPI_REGNOTINSTALLED ;
strlcpy ( ( void * ) serial , card - > serial , CAPI_SERIAL_LEN ) ;
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_get_serial ) ;
u16 capi20_get_profile ( u32 contr , struct capi_profile * profp )
{
struct capi_ctr * card ;
if ( contr = = 0 ) {
profp - > ncontroller = ncards ;
return CAPI_NOERROR ;
}
card = get_capi_ctr_by_nr ( contr ) ;
if ( ! card | | card - > cardstate ! = CARD_RUNNING )
return CAPI_REGNOTINSTALLED ;
memcpy ( ( void * ) profp , & card - > profile ,
sizeof ( struct capi_profile ) ) ;
return CAPI_NOERROR ;
}
EXPORT_SYMBOL ( capi20_get_profile ) ;
2008-04-28 13:14:42 +04:00
# ifdef AVMB1_COMPAT
2005-04-17 02:20:36 +04:00
static int old_capi_manufacturer ( unsigned int cmd , void __user * data )
{
avmb1_loadandconfigdef ldef ;
avmb1_extcarddef cdef ;
avmb1_resetdef rdef ;
capicardparams cparams ;
struct capi_ctr * card ;
struct capi_driver * driver = NULL ;
capiloaddata ldata ;
struct list_head * l ;
unsigned long flags ;
int retval ;
switch ( cmd ) {
case AVMB1_ADDCARD :
case AVMB1_ADDCARD_WITH_TYPE :
if ( cmd = = AVMB1_ADDCARD ) {
if ( ( retval = copy_from_user ( & cdef , data ,
sizeof ( avmb1_carddef ) ) ) )
return retval ;
cdef . cardtype = AVM_CARDTYPE_B1 ;
} else {
if ( ( retval = copy_from_user ( & cdef , data ,
sizeof ( avmb1_extcarddef ) ) ) )
return retval ;
}
cparams . port = cdef . port ;
cparams . irq = cdef . irq ;
cparams . cardnr = cdef . cardnr ;
read_lock_irqsave ( & capi_drivers_list_lock , flags ) ;
switch ( cdef . cardtype ) {
case AVM_CARDTYPE_B1 :
list_for_each ( l , & capi_drivers ) {
driver = list_entry ( l , struct capi_driver , list ) ;
if ( strcmp ( driver - > name , " b1isa " ) = = 0 )
break ;
}
break ;
case AVM_CARDTYPE_T1 :
list_for_each ( l , & capi_drivers ) {
driver = list_entry ( l , struct capi_driver , list ) ;
if ( strcmp ( driver - > name , " t1isa " ) = = 0 )
break ;
}
break ;
default :
driver = NULL ;
break ;
}
if ( ! driver ) {
read_unlock_irqrestore ( & capi_drivers_list_lock , flags ) ;
printk ( KERN_ERR " kcapi: driver not loaded. \n " ) ;
return - EIO ;
}
if ( ! driver - > add_card ) {
read_unlock_irqrestore ( & capi_drivers_list_lock , flags ) ;
printk ( KERN_ERR " kcapi: driver has no add card function. \n " ) ;
return - EIO ;
}
retval = driver - > add_card ( driver , & cparams ) ;
read_unlock_irqrestore ( & capi_drivers_list_lock , flags ) ;
return retval ;
case AVMB1_LOAD :
case AVMB1_LOAD_AND_CONFIG :
if ( cmd = = AVMB1_LOAD ) {
if ( copy_from_user ( & ldef , data ,
sizeof ( avmb1_loaddef ) ) )
return - EFAULT ;
ldef . t4config . len = 0 ;
ldef . t4config . data = NULL ;
} else {
if ( copy_from_user ( & ldef , data ,
sizeof ( avmb1_loadandconfigdef ) ) )
return - EFAULT ;
}
card = get_capi_ctr_by_nr ( ldef . contr ) ;
2007-10-16 12:27:52 +04:00
if ( ! card )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
card = capi_ctr_get ( card ) ;
if ( ! card )
return - ESRCH ;
2008-04-28 13:14:37 +04:00
if ( card - > load_firmware = = NULL ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " kcapi: load: no load function \n " ) ;
return - ESRCH ;
}
if ( ldef . t4file . len < = 0 ) {
printk ( KERN_DEBUG " kcapi: load: invalid parameter: length of t4file is %d ? \n " , ldef . t4file . len ) ;
return - EINVAL ;
}
2008-04-28 13:14:37 +04:00
if ( ldef . t4file . data = = NULL ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " kcapi: load: invalid parameter: dataptr is 0 \n " ) ;
return - EINVAL ;
}
ldata . firmware . user = 1 ;
ldata . firmware . data = ldef . t4file . data ;
ldata . firmware . len = ldef . t4file . len ;
ldata . configuration . user = 1 ;
ldata . configuration . data = ldef . t4config . data ;
ldata . configuration . len = ldef . t4config . len ;
if ( card - > cardstate ! = CARD_DETECTED ) {
printk ( KERN_INFO " kcapi: load: contr=%d not in detect state \n " , ldef . contr ) ;
return - EBUSY ;
}
card - > cardstate = CARD_LOADING ;
retval = card - > load_firmware ( card , & ldata ) ;
if ( retval ) {
card - > cardstate = CARD_DETECTED ;
capi_ctr_put ( card ) ;
return retval ;
}
while ( card - > cardstate ! = CARD_RUNNING ) {
msleep_interruptible ( 100 ) ; /* 0.1 sec */
if ( signal_pending ( current ) ) {
capi_ctr_put ( card ) ;
return - EINTR ;
}
}
capi_ctr_put ( card ) ;
return 0 ;
case AVMB1_RESETCARD :
if ( copy_from_user ( & rdef , data , sizeof ( avmb1_resetdef ) ) )
return - EFAULT ;
card = get_capi_ctr_by_nr ( rdef . contr ) ;
if ( ! card )
return - ESRCH ;
if ( card - > cardstate = = CARD_DETECTED )
return 0 ;
card - > reset_ctr ( card ) ;
while ( card - > cardstate > CARD_DETECTED ) {
msleep_interruptible ( 100 ) ; /* 0.1 sec */
if ( signal_pending ( current ) )
return - EINTR ;
}
return 0 ;
}
return - EINVAL ;
}
# endif
int capi20_manufacturer ( unsigned int cmd , void __user * data )
{
struct capi_ctr * card ;
switch ( cmd ) {
2008-04-28 13:14:42 +04:00
# ifdef AVMB1_COMPAT
2005-04-17 02:20:36 +04:00
case AVMB1_LOAD :
case AVMB1_LOAD_AND_CONFIG :
case AVMB1_RESETCARD :
case AVMB1_GET_CARDINFO :
case AVMB1_REMOVECARD :
return old_capi_manufacturer ( cmd , data ) ;
# endif
case KCAPI_CMD_TRACE :
{
kcapi_flagdef fdef ;
if ( copy_from_user ( & fdef , data , sizeof ( kcapi_flagdef ) ) )
return - EFAULT ;
card = get_capi_ctr_by_nr ( fdef . contr ) ;
if ( ! card )
return - ESRCH ;
card - > traceflag = fdef . flag ;
2007-03-01 07:13:50 +03:00
printk ( KERN_INFO " kcapi: contr [%03d] set trace=%d \n " ,
2005-04-17 02:20:36 +04:00
card - > cnr , card - > traceflag ) ;
return 0 ;
}
case KCAPI_CMD_ADDCARD :
{
struct list_head * l ;
struct capi_driver * driver = NULL ;
capicardparams cparams ;
kcapi_carddef cdef ;
int retval ;
if ( ( retval = copy_from_user ( & cdef , data , sizeof ( cdef ) ) ) )
return retval ;
cparams . port = cdef . port ;
cparams . irq = cdef . irq ;
cparams . membase = cdef . membase ;
cparams . cardnr = cdef . cardnr ;
cparams . cardtype = 0 ;
cdef . driver [ sizeof ( cdef . driver ) - 1 ] = 0 ;
list_for_each ( l , & capi_drivers ) {
driver = list_entry ( l , struct capi_driver , list ) ;
if ( strcmp ( driver - > name , cdef . driver ) = = 0 )
break ;
}
2008-04-28 13:14:37 +04:00
if ( driver = = NULL ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " kcapi: driver \" %s \" not loaded. \n " ,
cdef . driver ) ;
return - ESRCH ;
}
if ( ! driver - > add_card ) {
printk ( KERN_ERR " kcapi: driver \" %s \" has no add card function. \n " , cdef . driver ) ;
return - EIO ;
}
return driver - > add_card ( driver , & cparams ) ;
}
default :
printk ( KERN_ERR " kcapi: manufacturer command %d unknown. \n " ,
cmd ) ;
break ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( capi20_manufacturer ) ;
/* temporary hack */
void capi20_set_callback ( struct capi20_appl * ap ,
void ( * callback ) ( unsigned int cmd , __u32 contr , void * data ) )
{
ap - > callback = callback ;
}
EXPORT_SYMBOL ( capi20_set_callback ) ;
/* ------------------------------------------------------------- */
/* -------- Init & Cleanup ------------------------------------- */
/* ------------------------------------------------------------- */
/*
* init / exit functions
*/
static int __init kcapi_init ( void )
{
char * p ;
char rev [ 32 ] ;
2007-03-01 07:13:50 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
2007-03-01 07:13:50 +03:00
ret = cdebug_init ( ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
kcapi_proc_init ( ) ;
2008-04-28 13:14:37 +04:00
if ( ( p = strchr ( revision , ' : ' ) ) ! = NULL & & p [ 1 ] ) {
2005-04-17 02:20:36 +04:00
strlcpy ( rev , p + 2 , sizeof ( rev ) ) ;
2008-04-28 13:14:37 +04:00
if ( ( p = strchr ( rev , ' $ ' ) ) ! = NULL & & p > rev )
2005-04-17 02:20:36 +04:00
* ( p - 1 ) = 0 ;
} else
strcpy ( rev , " 1.0 " ) ;
printk ( KERN_NOTICE " CAPI Subsystem Rev %s \n " , rev ) ;
return 0 ;
}
static void __exit kcapi_exit ( void )
{
kcapi_proc_exit ( ) ;
/* make sure all notifiers are finished */
flush_scheduled_work ( ) ;
2007-03-01 07:13:50 +03:00
cdebug_exit ( ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( kcapi_init ) ;
module_exit ( kcapi_exit ) ;