mISDN/drivers/isdn/hardware/mISDN/core.c

404 lines
8.1 KiB
C
Raw Normal View History

2001-02-11 22:46:19 +00:00
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/config.h>
#include <linux/module.h>
#include "hisax_core.h"
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
hisaxobject_t *hisax_objects = NULL;
2001-02-22 10:14:16 +00:00
int core_debug;
2001-03-11 21:23:39 +00:00
static int debug;
static int obj_id;
2001-02-11 22:46:19 +00:00
#ifdef MODULE
MODULE_AUTHOR("Karsten Keil");
MODULE_PARM(debug, "1i");
EXPORT_SYMBOL(HiSax_register);
EXPORT_SYMBOL(HiSax_unregister);
#define HiSaxInit init_module
#endif
static moditem_t modlist[] = {
2001-03-04 17:08:33 +00:00
{"hisaxl1", ISDN_PID_L1_TE_S0},
{"hisaxl2", ISDN_PID_L2_LAPD},
{"hisaxl2", ISDN_PID_L2_B_X75SLP},
{NULL, ISDN_PID_NONE}
2001-02-11 22:46:19 +00:00
};
2001-04-08 16:45:56 +00:00
hisaxobject_t *
get_object(int id) {
hisaxobject_t *obj = hisax_objects;
while(obj) {
if (obj->id == id)
return(obj);
obj = obj->next;
}
return(NULL);
}
2001-02-11 22:46:19 +00:00
static hisaxobject_t *
2001-03-04 17:08:33 +00:00
find_object(int protocol) {
2001-02-11 22:46:19 +00:00
hisaxobject_t *obj = hisax_objects;
2001-03-04 17:08:33 +00:00
int err;
2001-02-11 22:46:19 +00:00
while (obj) {
2001-03-04 17:08:33 +00:00
err = obj->own_ctrl(NULL, MGR_HASPROTOCOL | REQUEST, &protocol);
if (!err)
return(obj);
if (err != -ENOPROTOOPT) {
if (HasProtocol(obj, protocol))
return(obj);
}
2001-02-11 22:46:19 +00:00
obj = obj->next;
}
return(NULL);
}
static hisaxobject_t *
2001-03-04 17:08:33 +00:00
find_object_module(int protocol) {
2001-02-11 22:46:19 +00:00
moditem_t *m = modlist;
hisaxobject_t *obj;
while (m->name != NULL) {
2001-03-04 17:08:33 +00:00
if (m->protocol == protocol) {
2001-02-11 22:46:19 +00:00
#ifdef CONFIG_KMOD
2001-03-04 17:08:33 +00:00
if (debug)
printk(KERN_DEBUG
"find_object_module %s - trying to load\n",
2001-02-11 22:46:19 +00:00
m->name);
2001-03-04 17:08:33 +00:00
request_module(m->name);
#else
printk(KERN_WARNING "not possible to autoload %s please try to load manually\n",
m->name);
2001-02-11 22:46:19 +00:00
#endif
2001-03-04 17:08:33 +00:00
if ((obj = find_object(protocol)))
return(obj);
2001-02-11 22:46:19 +00:00
}
m++;
}
if (debug)
2001-03-04 17:08:33 +00:00
printk(KERN_DEBUG __FUNCTION__": no module for protocol %x found\n",
protocol);
2001-02-11 22:46:19 +00:00
return(NULL);
}
static void
remove_object(hisaxobject_t *obj) {
hisaxstack_t *st = hisax_stacklist;
2001-03-03 08:07:30 +00:00
hisaxlayer_t *layer;
2001-02-11 22:46:19 +00:00
hisaxinstance_t *inst, *tmp;
while (st) {
2001-03-03 08:07:30 +00:00
layer = st->lstack;
while(layer) {
inst = layer->inst;
2001-02-11 22:46:19 +00:00
while (inst) {
if (inst->obj == obj) {
tmp = inst->next;
inst->obj->own_ctrl(st, MGR_RELEASE
| INDICATION, inst);
inst = tmp;
} else
inst = inst->next;
}
2001-03-03 08:07:30 +00:00
layer = layer->next;
2001-02-11 22:46:19 +00:00
}
st = st->next;
}
}
static int
2001-08-02 14:51:56 +00:00
dummy_if(hisaxif_t *hif, struct sk_buff *skb)
{
if (!skb) {
printk(KERN_WARNING __FUNCTION__": hif(%p) without skb\n",
hif);
return(-EINVAL);
}
2001-02-11 22:46:19 +00:00
if (debug & DEBUG_DUMMY_FUNC)
2001-08-02 14:51:56 +00:00
printk(KERN_DEBUG __FUNCTION__": hif(%p) skb(%p) len(%d) prim(%x)\n",
hif, skb, skb->len, *((u_int *)skb->data));
2001-11-02 23:41:26 +00:00
dev_kfree_skb_any(skb);
2001-08-02 14:51:56 +00:00
return(0);
2001-02-11 22:46:19 +00:00
}
2001-03-26 11:40:02 +00:00
hisaxinstance_t *
get_next_instance(hisaxstack_t *st, hisax_pid_t *pid)
{
int err;
hisaxinstance_t *next;
int layer, proto;
hisaxobject_t *obj;
layer = get_lowlayer(pid->layermask);
proto = pid->protocol[layer];
next = get_instance(st, layer, proto);
if (!next) {
obj = find_object(proto);
if (!obj)
obj = find_object_module(proto);
if (!obj) {
printk(KERN_WARNING __FUNCTION__": no object found\n");
return(NULL);
}
err = obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid);
if (err) {
printk(KERN_WARNING __FUNCTION__": newlayer err(%d)\n",
err);
return(NULL);
}
next = get_instance(st, layer, proto);
2001-02-11 22:46:19 +00:00
}
2001-03-26 11:40:02 +00:00
return(next);
2001-02-11 22:46:19 +00:00
}
2001-11-14 10:41:26 +00:00
static int
sel_channel(hisaxstack_t *st, channel_info_t *ci)
{
int err = -EINVAL;
if (!ci)
return(err);
printk(KERN_DEBUG __FUNCTION__": st(%p) st->mgr(%p)\n",
st, st->mgr);
if (st->mgr) {
if (st->mgr->obj && st->mgr->obj->own_ctrl) {
err = st->mgr->obj->own_ctrl(st->mgr,
MGR_SELCHANNEL | REQUEST, ci);
printk(KERN_DEBUG __FUNCTION__": MGR_SELCHANNEL(%d)\n",
err);
} else
int_error();
} else {
printk(KERN_WARNING __FUNCTION__": no mgr st(%p)\n", st);
}
if (err) {
hisaxstack_t *cst = st->child;
int nr = 0;
ci->st.p = NULL;
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
while(cst) {
nr++;
if (nr == (ci->channel & 3)) {
ci->st.p = cst;
err = 0;
break;
}
cst = cst->next;
}
}
}
return(err);
}
2001-02-11 22:46:19 +00:00
static int
2001-03-26 11:40:02 +00:00
disconnect_if(hisaxinstance_t *inst, u_int prim, hisaxif_t *hif) {
int err = 0;
2001-02-11 22:46:19 +00:00
2001-03-26 11:40:02 +00:00
if (hif) {
hif->stat = IF_NOACTIV;
hif->func = dummy_if;
hif->peer = NULL;
hif->fdata = NULL;
2001-02-11 22:46:19 +00:00
}
2001-03-26 11:40:02 +00:00
if (inst)
err = inst->obj->own_ctrl(inst, prim, hif);
return(err);
2001-02-11 22:46:19 +00:00
}
2001-04-11 10:21:10 +00:00
static int
add_if(hisaxinstance_t *inst, u_int prim, hisaxif_t *hif) {
hisaxif_t *myif;
if (!inst)
return(-EINVAL);
if (!hif)
return(-EINVAL);
if (hif->stat & IF_UP) {
myif = &inst->down;
} else if (hif->stat & IF_DOWN) {
myif = &inst->up;
} else
return(-EINVAL);
APPEND_TO_LIST(hif, myif);
inst->obj->own_ctrl(inst, prim, hif);
return(0);
}
2001-02-11 22:46:19 +00:00
static char tmpbuf[4096];
static int
debugout(hisaxinstance_t *inst, logdata_t *log)
{
char *p = tmpbuf;
if (log->head && *log->head)
p += sprintf(p,"%s ", log->head);
else
p += sprintf(p,"%s ", inst->obj->name);
p += vsprintf(p, log->fmt, log->args);
printk(KERN_DEBUG "%s\n", tmpbuf);
return(0);
}
2001-09-29 20:05:01 +00:00
static int
get_hdevice(hisaxdevice_t **dev, int *typ)
{
if (!dev)
return(-EINVAL);
if (!typ)
return(-EINVAL);
if (*typ == HISAX_RAW_DEVICE) {
*dev = get_free_rawdevice();
if (!(*dev))
return(-ENODEV);
return(0);
}
return(-EINVAL);
}
2001-02-11 22:46:19 +00:00
static int central_manager(void *data, u_int prim, void *arg) {
hisaxstack_t *st = data;
switch(prim) {
2001-03-26 11:40:02 +00:00
case MGR_NEWSTACK | REQUEST:
if (!(st = new_stack(data, arg)))
2001-02-27 17:45:44 +00:00
return(-EINVAL);
return(0);
2001-03-26 11:40:02 +00:00
case MGR_REGLAYER | INDICATION:
2001-03-03 08:07:30 +00:00
return(register_layer(st, arg));
2001-03-26 11:40:02 +00:00
case MGR_REGLAYER | REQUEST:
2001-03-03 08:07:30 +00:00
if (!register_layer(st, arg)) {
2001-02-27 17:45:44 +00:00
hisaxinstance_t *inst = arg;
2001-03-26 11:40:02 +00:00
return(inst->obj->own_ctrl(arg, MGR_REGLAYER | CONFIRM, NULL));
2001-02-27 17:45:44 +00:00
}
2001-03-26 11:40:02 +00:00
return(-EINVAL);
case MGR_UNREGLAYER | REQUEST:
2001-03-27 15:34:20 +00:00
return(unregister_instance(data));
2001-03-26 11:40:02 +00:00
case MGR_DISCONNECT | REQUEST:
case MGR_DISCONNECT | INDICATION:
return(disconnect_if(data, prim, arg));
2001-09-29 20:05:01 +00:00
case MGR_GETDEVICE | REQUEST:
return(get_hdevice(data, arg));
case MGR_DELDEVICE | REQUEST:
return(free_device(data));
2001-05-18 00:48:52 +00:00
}
if (!data)
return(-EINVAL);
switch(prim) {
case MGR_SETSTACK | REQUEST:
return(set_stack(st, arg));
case MGR_CLEARSTACK | REQUEST:
return(clear_stack(st));
case MGR_DELSTACK | REQUEST:
return(release_stack(st));
2001-11-14 10:41:26 +00:00
case MGR_SELCHANNEL | REQUEST:
return(sel_channel(st, arg));
2001-04-11 10:21:10 +00:00
case MGR_ADDIF | REQUEST:
return(add_if(data, prim, arg));
2001-03-27 15:34:20 +00:00
case MGR_CONNECT | REQUEST:
return(ConnectIF(data, arg));
2001-02-27 17:45:44 +00:00
case MGR_LOADFIRM | REQUEST:
if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl)
2001-03-26 11:40:02 +00:00
return(st->mgr->obj->own_ctrl(st->mgr, prim, arg));
2001-02-27 17:45:44 +00:00
break;
2001-02-11 22:46:19 +00:00
case MGR_DEBUGDATA | REQUEST:
return(debugout(data, arg));
default:
printk(KERN_WARNING "manager prim %x not handled\n", prim);
break;
}
return(-EINVAL);
}
void
hisaxlock_core(void) {
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
void
hisaxunlock_core(void) {
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
int HiSax_register(hisaxobject_t *obj) {
if (!obj)
return(-EINVAL);
2001-03-11 21:23:39 +00:00
obj->id = obj_id++;
2001-02-11 22:46:19 +00:00
APPEND_TO_LIST(obj, hisax_objects);
obj->ctrl = central_manager;
// register_prop
if (debug)
2001-03-11 21:23:39 +00:00
printk(KERN_DEBUG "HiSax_register %s id %x\n", obj->name,
obj->id);
2001-02-11 22:46:19 +00:00
return(0);
}
int HiSax_unregister(hisaxobject_t *obj) {
if (!obj)
return(-EINVAL);
if (debug)
printk(KERN_DEBUG "HiSax_unregister %s %d refs\n",
obj->name, obj->refcnt);
2001-03-04 17:08:33 +00:00
if (obj->DPROTO.protocol[0])
2001-02-11 22:46:19 +00:00
release_stacks(obj);
else
remove_object(obj);
REMOVE_FROM_LISTBASE(obj, hisax_objects);
return(0);
}
int
HiSaxInit(void)
{
int err;
2001-02-22 10:14:16 +00:00
core_debug = debug;
2001-02-11 22:46:19 +00:00
err = init_hisaxdev(debug);
return(err);
}
#ifdef MODULE
void cleanup_module(void) {
2001-03-03 08:07:30 +00:00
hisaxstack_t *st;
2001-02-11 22:46:19 +00:00
free_hisaxdev();
if (hisax_objects) {
printk(KERN_WARNING "hisaxcore hisax_objects not empty\n");
}
if (hisax_stacklist) {
printk(KERN_WARNING "hisaxcore hisax_stacklist not empty\n");
2001-03-03 08:07:30 +00:00
st = hisax_stacklist;
while (st) {
printk(KERN_WARNING "hisaxcore st %x in list\n",
st->id);
if (st == st->next) {
printk(KERN_WARNING "hisaxcore st == next\n");
break;
}
st = st->next;
}
2001-02-11 22:46:19 +00:00
}
printk(KERN_DEBUG "hisaxcore unloaded\n");
}
#endif