132 lines
2.9 KiB
C
132 lines
2.9 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 "hisaxl1.h"
|
|
#include "helper.h"
|
|
#include "hisax_dch.h"
|
|
|
|
static void
|
|
dchannel_bh(dchannel_t *dch)
|
|
{
|
|
struct sk_buff *skb;
|
|
int err;
|
|
|
|
if (!dch)
|
|
return;
|
|
if (dch->debug)
|
|
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
|
|
#if 0
|
|
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
|
|
if (dch->debug)
|
|
debugprint(&dch->inst, "D-Channel Busy cleared");
|
|
stptr = dch->stlist;
|
|
while (stptr != NULL) {
|
|
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
|
|
stptr = stptr->next;
|
|
}
|
|
}
|
|
#endif
|
|
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
|
|
if ((skb = dch->next_skb)) {
|
|
dch->next_skb = NULL;
|
|
skb_trim(skb, 0);
|
|
if (if_newhead(&dch->inst.up, PH_DATA_CNF, DINFO_SKB, skb))
|
|
dev_kfree_skb(skb);
|
|
}
|
|
}
|
|
|
|
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event)) {
|
|
while ((skb = skb_dequeue(&dch->rqueue))) {
|
|
err = if_newhead(&dch->inst.up, PH_DATA_IND, DINFO_SKB, skb);
|
|
if (err < 0) {
|
|
printk(KERN_WARNING "%s: deliver err %d\n", __FUNCTION__, err);
|
|
dev_kfree_skb(skb);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dch->hw_bh)
|
|
dch->hw_bh(dch);
|
|
}
|
|
|
|
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->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;
|
|
return(-ENOMEM);
|
|
}
|
|
dch->hw = NULL;
|
|
dch->rx_skb = NULL;
|
|
dch->tx_idx = 0;
|
|
dch->next_skb = NULL;
|
|
dch->event = 0;
|
|
dch->tqueue.data = dch;
|
|
dch->tqueue.routine = (void *) (void *) dchannel_bh;
|
|
dch->hw_bh = NULL;
|
|
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_skb) {
|
|
dev_kfree_skb(dch->rx_skb);
|
|
dch->rx_skb = 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);
|
|
}
|
|
|
|
void
|
|
set_dchannel_pid(hisax_pid_t *pid, int protocol, int layermask) {
|
|
|
|
if (!layermask)
|
|
layermask = ISDN_LAYER(0)| ISDN_LAYER(1) | ISDN_LAYER(2) |
|
|
ISDN_LAYER(3) | ISDN_LAYER(4);
|
|
|
|
memset(pid, 0, sizeof(hisax_pid_t));
|
|
pid->layermask = layermask;
|
|
if (layermask & ISDN_LAYER(0))
|
|
pid->protocol[0] = ISDN_PID_L0_TE_S0;
|
|
if (layermask & ISDN_LAYER(1))
|
|
pid->protocol[1] = ISDN_PID_L1_TE_S0;
|
|
if (layermask & ISDN_LAYER(2))
|
|
pid->protocol[2] = ISDN_PID_L2_LAPD;
|
|
if (layermask & ISDN_LAYER(3)) {
|
|
if (protocol == 2)
|
|
pid->protocol[3] = ISDN_PID_L3_DSS1USER;
|
|
}
|
|
if (layermask & ISDN_LAYER(4))
|
|
pid->protocol[4] = ISDN_PID_L4_CAPI20;
|
|
}
|