mISDN/drivers/isdn/hardware/mISDN/capi.c

289 lines
6.3 KiB
C

/* $Id$
*
*/
#include <linux/module.h>
#include "hisax_capi.h"
#include "helper.h"
#include "debug.h"
const char *capi_revision = "$Revision$";
static int debug = 0;
static hisaxobject_t capi_obj;
static char MName[] = "HiSax Capi 2.0";
static int Capi20Protocols[] = { ISDN_PID_CAPI20
};
#define PROTOCOLCNT (sizeof(Capi20Protocols)/sizeof(int))
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
MODULE_PARM(debug, "1i");
#define Capi20Init init_module
#endif
static char deb_buf[256];
void capidebug(int level, char *fmt, ...)
{
va_list args;
if (debug & level) {
va_start(args, fmt);
vsprintf(deb_buf, fmt, args);
printk(KERN_DEBUG "%s\n", deb_buf);
va_end(args);
}
}
// ---------------------------------------------------------------------------
// registration to kernelcapi
int hisax_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
Contr_t *contr = ctrl->driverdata;
printk(KERN_INFO __FUNCTION__ "\n");
contrLoadFirmware(contr);
return 0;
}
void hisax_reset_ctr(struct capi_ctr *ctrl)
{
Contr_t *contr = ctrl->driverdata;
printk(KERN_INFO __FUNCTION__ "\n");
contrReset(contr);
}
void hisax_remove_ctr(struct capi_ctr *ctrl)
{
printk(KERN_INFO __FUNCTION__ "\n");
int_error();
}
static char *hisax_procinfo(struct capi_ctr *ctrl)
{
Contr_t *contr = (ctrl->driverdata);
printk(KERN_INFO __FUNCTION__ "\n");
if (!contr)
return "";
sprintf(contr->infobuf, "-");
return contr->infobuf;
}
void hisax_register_appl(struct capi_ctr *ctrl,
__u16 ApplId, capi_register_params *rp)
{
Contr_t *contr = ctrl->driverdata;
printk(KERN_INFO __FUNCTION__ "\n");
contrRegisterAppl(contr, ApplId, rp);
}
void hisax_release_appl(struct capi_ctr *ctrl, __u16 ApplId)
{
Contr_t *contr = ctrl->driverdata;
printk(KERN_INFO __FUNCTION__ "\n");
contrReleaseAppl(contr, ApplId);
}
void hisax_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
Contr_t *contr = ctrl->driverdata;
contrSendMessage(contr, skb);
}
static int hisax_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
int len = 0;
len += sprintf(page+len, "hisax_read_proc\n");
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
};
struct capi_driver_interface *cdrv_if;
struct capi_driver hisax_driver = {
"hisax",
"0.01",
hisax_load_firmware,
hisax_reset_ctr,
hisax_remove_ctr,
hisax_register_appl,
hisax_release_appl,
hisax_send_message,
hisax_procinfo,
hisax_read_proc,
0,
0,
};
int CapiNew(void)
{
char tmp[64];
strcpy(tmp, capi_revision);
printk(KERN_INFO "HiSax: CAPI Revision %s\n", HiSax_getrev(tmp));
cdrv_if = attach_capi_driver(&hisax_driver);
if (!cdrv_if) {
printk(KERN_ERR "hisax: failed to attach capi_driver\n");
return -EIO;
}
init_listen();
init_cplci();
init_ncci();
return 0;
}
static int
add_if_contr(Contr_t *ctrl, hisaxif_t *hif) {
int err;
hisaxinstance_t *inst = &ctrl->inst;
printk(KERN_DEBUG "capi add_if lay %d/%x prot %x\n", hif->layer,
hif->stat, hif->protocol);
if (IF_TYPE(hif) == IF_UP) {
printk(KERN_WARNING "capi add_if here is no UP interface\n");
} else if (IF_TYPE(hif) == IF_DOWN) {
hif->fdata = ctrl;
hif->func = contrL3L4;
if (inst->down.stat == IF_NOACTIV) {
inst->down.stat = IF_UP;
inst->down.protocol =
inst->st->protocols[inst->down.layer];
err = capi_obj.ctrl(inst->st, MGR_ADDIF | REQUEST, &inst->down);
if (err)
inst->down.stat = IF_NOACTIV;
}
} else
return(-EINVAL);
return(0);
}
static int
del_if(hisaxinstance_t *inst, hisaxif_t *hif) {
int err;
printk(KERN_DEBUG "capi del_if lay %d/%x %p/%p\n", hif->layer,
hif->stat, hif->func, hif->fdata);
if ((hif->func == inst->up.func) && (hif->fdata == inst->up.fdata)) {
inst->up.stat = IF_NOACTIV;
inst->up.protocol = ISDN_PID_NONE;
err = capi_obj.ctrl(inst->st, MGR_ADDIF | REQUEST, &inst->up);
} else if ((hif->func == inst->down.func) && (hif->fdata == inst->down.fdata)) {
inst->down.stat = IF_NOACTIV;
inst->down.protocol = ISDN_PID_NONE;
err = capi_obj.ctrl(inst->st, MGR_ADDIF | REQUEST, &inst->down);
} else {
printk(KERN_DEBUG "capi del_if no if found\n");
return(-EINVAL);
}
return(0);
}
static int
capi20_manager(void *data, u_int prim, void *arg) {
hisaxstack_t *st = data;
Contr_t *ctrl = (Contr_t *)capi_obj.ilist;
// printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
if (!data)
return(-EINVAL);
while(ctrl) {
if (ctrl->inst.st == st)
break;
ctrl = ctrl->next;
}
switch(prim) {
case MGR_ADDIF | REQUEST:
if (!ctrl)
ctrl = newContr(&capi_obj, st, arg);
if (!ctrl) {
printk(KERN_WARNING "capi20_manager create_ctrl failed\n");
return(-EINVAL);
}
return(add_if_contr(ctrl, arg));
break;
case MGR_DELIF | REQUEST:
if (!ctrl) {
printk(KERN_WARNING "capi20_manager delif no instance\n");
return(-EINVAL);
}
return(del_if(&ctrl->inst, arg));
break;
case MGR_RELEASE | INDICATION:
if (ctrl) {
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
delContr(ctrl);
} else
printk(KERN_WARNING "capi20_manager release no instance\n");
break;
default:
printk(KERN_WARNING "capi20_manager prim %x not handled\n", prim);
return(-EINVAL);
}
return(0);
}
int Capi20Init(void)
{
int err;
capi_obj.name = MName;
capi_obj.protocols = Capi20Protocols;
capi_obj.protcnt = PROTOCOLCNT;
capi_obj.own_ctrl = capi20_manager;
capi_obj.prev = NULL;
capi_obj.next = NULL;
capi_obj.ilist = NULL;
capi_obj.layer = 4;
if ((err = CapiNew()))
return(err);
if ((err = HiSax_register(&capi_obj))) {
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
detach_capi_driver(&hisax_driver);
free_listen();
free_cplci();
free_ncci();
}
return(err);
}
#ifdef MODULE
void cleanup_module(void)
{
int err;
Contr_t *contrlist = (Contr_t *)capi_obj.ilist;
if ((err = HiSax_unregister(&capi_obj))) {
printk(KERN_ERR "Can't unregister User DSS1 error(%d)\n", err);
}
if (contrlist) {
printk(KERN_WARNING "hisaxl3 contrlist not empty\n");
while(contrlist)
delContr(contrlist);
capi_obj.ilist = NULL;
}
detach_capi_driver(&hisax_driver);
free_listen();
free_cplci();
free_ncci();
}
#endif