mISDN/drivers/isdn/hardware/mISDN/helper.c

258 lines
4.8 KiB
C

/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define __NO_VERSION__
#include <linux/hisaxif.h>
#include "helper.h"
#include "hisax_hw.h"
int
discard_queue(struct sk_buff_head *q)
{
struct sk_buff *skb;
int ret=0;
while ((skb = skb_dequeue(q))) {
dev_kfree_skb(skb);
ret++;
}
return(ret);
}
int
init_dchannel(dchannel_t *dch) {
if (!(dch->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for dlog\n");
return(-ENOMEM);
}
if (!(dch->rx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for dchannel rx_buf\n");
kfree(dch->dlog);
dch->dlog = NULL;
return(-ENOMEM);
}
dch->rx_idx = 0;
if (!(dch->tx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for dchannel tx_buf\n");
kfree(dch->dlog);
dch->dlog = NULL;
kfree(dch->rx_buf);
dch->rx_buf = NULL;
return(-ENOMEM);
}
dch->tx_idx = 0;
dch->next_skb = NULL;
dch->event = 0;
dch->tqueue.data = dch;
skb_queue_head_init(&dch->rqueue);
return(0);
}
int
free_dchannel(dchannel_t *dch) {
if (dch->tqueue.sync)
printk(KERN_ERR"free_dchannel tqueue.sync\n");
discard_queue(&dch->rqueue);
if (dch->rx_buf) {
kfree(dch->rx_buf);
dch->rx_buf = NULL;
}
if (dch->tx_buf) {
kfree(dch->tx_buf);
dch->tx_buf = NULL;
}
if (dch->next_skb) {
dev_kfree_skb(dch->next_skb);
dch->next_skb = NULL;
}
if (dch->dlog) {
kfree(dch->dlog);
dch->dlog = NULL;
}
return(0);
}
int
init_bchannel(bchannel_t *bch) {
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bchannel rx_buf\n");
return (-ENOMEM);
}
if (!(bch->tx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bchannel tx_buf\n");
kfree(bch->rx_buf);
bch->rx_buf = NULL;
return (-ENOMEM);
}
skb_queue_head_init(&bch->rqueue);
bch->next_skb = NULL;
bch->Flag = 0;
bch->event = 0;
bch->rx_idx = 0;
bch->tx_len = 0;
bch->tx_idx = 0;
bch->tqueue.data = bch;
return(0);
}
int
free_bchannel(bchannel_t *bch) {
if (bch->tqueue.sync)
printk(KERN_ERR"free_bchannel tqueue.sync\n");
discard_queue(&bch->rqueue);
if (bch->rx_buf) {
kfree(bch->rx_buf);
bch->rx_buf = NULL;
}
if (bch->tx_buf) {
kfree(bch->tx_buf);
bch->tx_buf = NULL;
}
if (bch->next_skb) {
dev_kfree_skb(bch->next_skb);
bch->next_skb = NULL;
}
return(0);
}
int bprotocol2pid(void *bp, hisax_pid_t *pid) {
__u8 *p = bp;
__u16 *w = bp;
int i;
p += 6;
for (i=1; i<=3; i++) {
if (*w > 23) {
int_errtxt("L%d pid %x\n",i,*w);
return(-EINVAL);
}
pid->protocol[i] = (1 <<*w) | ISDN_PID_LAYER(i) |
ISDN_PID_BCHANNEL_BIT;
if (*p)
pid->param[i] = p;
else
pid->param[i] = NULL;
w++;
p += *p;
p++;
}
if (*p)
pid->global = p;
else
pid->global = NULL;
return(0);
}
int HasProtocol(hisaxinstance_t *inst, int proto) {
int i;
if (!inst || !inst->obj) {
int_error();
return(0);
}
for (i=0; i<inst->obj->protcnt; i++) {
if (proto == inst->obj->protocols[i])
return(1);
}
return(0);
}
int
layermask2layer(int layermask) {
switch(layermask) {
case ISDN_LAYER(0): return(0);
case ISDN_LAYER(1): return(1);
case ISDN_LAYER(2): return(2);
case ISDN_LAYER(3): return(3);
case ISDN_LAYER(4): return(4);
case ISDN_LAYER(5): return(5);
case ISDN_LAYER(6): return(6);
case ISDN_LAYER(7): return(7);
case 0: return(-1);
}
return(-2);
}
int
get_protocol(hisaxstack_t *st, int layermask)
{
int layer = layermask2layer(layermask);
if (!st){
int_error();
return(-EINVAL);
}
if (layer<0) {
int_errtxt("lmask(%x) layer(%x) st(%x)",
layermask, layer, st->id);
return(-EINVAL);
}
return(st->pid.protocol[layer]);
}
int get_down_layer(int layermask) {
int downlayer = 2;
if (layermask>255 || (layermask & 1)) {
int_errtxt("lmask %x out of range", layermask);
return(0);
}
while(downlayer & 0xFF) {
if (downlayer & layermask)
break;
downlayer <<= 1;
}
if (downlayer & 0xFF)
downlayer >>= 1;
else
downlayer = 0;
return(downlayer);
}
int get_up_layer(int layermask) {
int uplayer = 0x40;
if (layermask>=128) {
int_errtxt("lmask %x out of range", layermask);
return(0);
}
while(uplayer) {
if (uplayer & layermask)
break;
uplayer >>= 1;
}
if (uplayer)
uplayer <<= 1;
else
uplayer = 1;
return(uplayer);
}
int DelIF(hisaxinstance_t *inst, hisaxif_t *mif, void *func, void *data) {
hisaxif_t hif;
memset(&hif, 0, sizeof(hisaxif_t));
hif.protocol = mif->protocol;
hif.layermask = mif->layermask;
hif.fdata = data;
hif.func = func;
hif.func(&hif, MGR_DELIF | REQUEST, 0, 0, NULL);
mif->protocol = ISDN_PID_NONE;
inst->obj->ctrl(inst->st, MGR_ADDIF | REQUEST, mif);
return(inst->obj->ctrl(inst->st, MGR_DELIF | REQUEST, &hif));
}