📄 eicon_idi.c
字号:
/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface * * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH * for sponsoring and testing fax * capabilities with Diva Server cards. * (dor@deutschemailbox.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/config.h>#define __NO_VERSION__#include "eicon.h"#include "eicon_idi.h"#include "eicon_dsp.h"#include "uxio.h"#undef EICON_FULL_SERVICE_OKTETTchar *eicon_idi_revision = "$Revision: 1.41 $";eicon_manifbuf *manbuf;int eicon_idi_manage_assign(eicon_card *card);int eicon_idi_manage_remove(eicon_card *card);int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);intidi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan){ int l = 0; int tmp; tmp = 0; if (!signet) { /* Signal Layer */ reqbuf->XBuffer.P[l++] = CAI; reqbuf->XBuffer.P[l++] = 1; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = KEY; reqbuf->XBuffer.P[l++] = 3; reqbuf->XBuffer.P[l++] = 'I'; reqbuf->XBuffer.P[l++] = '4'; reqbuf->XBuffer.P[l++] = 'L'; reqbuf->XBuffer.P[l++] = SHIFT|6; reqbuf->XBuffer.P[l++] = SIN; reqbuf->XBuffer.P[l++] = 2; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; reqbuf->ReqId = DSIG_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ } else { /* Network Layer */ reqbuf->XBuffer.P[l++] = CAI; reqbuf->XBuffer.P[l++] = 1; reqbuf->XBuffer.P[l++] = chan->e.D3Id; reqbuf->XBuffer.P[l++] = LLC; reqbuf->XBuffer.P[l++] = 2; switch(chan->l2prot) { case ISDN_PROTO_L2_V11096: case ISDN_PROTO_L2_V11019: case ISDN_PROTO_L2_V11038: case ISDN_PROTO_L2_TRANS: reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: reqbuf->XBuffer.P[l++] = 5; /* X.75 */ break; case ISDN_PROTO_L2_MODEM: if (chan->fsm_state == EICON_STATE_IWAIT) reqbuf->XBuffer.P[l++] = 9; /* V.42 incoming */ else reqbuf->XBuffer.P[l++] = 10; /* V.42 */ break; case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_FAX: if (chan->fsm_state == EICON_STATE_IWAIT) reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */ else reqbuf->XBuffer.P[l++] = 2; /* transparent */ break; default: reqbuf->XBuffer.P[l++] = 1; } switch(chan->l3prot) { case ISDN_PROTO_L3_FCLASS2:#ifdef CONFIG_ISDN_TTY_FAX reqbuf->XBuffer.P[l++] = 6; reqbuf->XBuffer.P[l++] = NLC; tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]); reqbuf->XBuffer.P[l++] = tmp; l += tmp; break;#endif case ISDN_PROTO_L3_TRANS: default: reqbuf->XBuffer.P[l++] = 4; } reqbuf->XBuffer.P[l++] = 0; /* end */ reqbuf->Req = ASSIGN; reqbuf->ReqCh = 0; reqbuf->ReqId = NL_ID; reqbuf->XBuffer.length = l; reqbuf->Reference = 1; /* Net Entity */ } return(0);}intidi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch){ reqbuf->Req = rq; reqbuf->ReqCh = Ch; reqbuf->ReqId = 1; reqbuf->XBuffer.length = 1; reqbuf->XBuffer.P[0] = 0; reqbuf->Reference = signet; return(0);}intidi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan){ reqbuf->Req = SUSPEND; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.P[0] = CAI; reqbuf->XBuffer.P[1] = 1; reqbuf->XBuffer.P[2] = chan->No; reqbuf->XBuffer.P[3] = 0; reqbuf->XBuffer.length = 4; reqbuf->Reference = 0; /* Sig Entity */ return(0);}intidi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan){ int l = 9; reqbuf->Req = CALL_RES; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; reqbuf->XBuffer.P[0] = CAI; reqbuf->XBuffer.P[1] = 6; reqbuf->XBuffer.P[2] = 9; reqbuf->XBuffer.P[3] = 0; reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 32; reqbuf->XBuffer.P[7] = 0; switch(chan->l2prot) { case ISDN_PROTO_L2_X75I: case ISDN_PROTO_L2_X75UI: case ISDN_PROTO_L2_X75BUI: case ISDN_PROTO_L2_HDLC: reqbuf->XBuffer.P[1] = 1; reqbuf->XBuffer.P[2] = 0x05; l = 4; break; case ISDN_PROTO_L2_V11096: reqbuf->XBuffer.P[2] = 0x0d; reqbuf->XBuffer.P[3] = 5; reqbuf->XBuffer.P[4] = 0; break; case ISDN_PROTO_L2_V11019: reqbuf->XBuffer.P[2] = 0x0d; reqbuf->XBuffer.P[3] = 6; reqbuf->XBuffer.P[4] = 0; break; case ISDN_PROTO_L2_V11038: reqbuf->XBuffer.P[2] = 0x0d; reqbuf->XBuffer.P[3] = 7; reqbuf->XBuffer.P[4] = 0; break; case ISDN_PROTO_L2_MODEM: reqbuf->XBuffer.P[2] = 0x11; reqbuf->XBuffer.P[3] = 7; reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 128; reqbuf->XBuffer.P[7] = 0; break; case ISDN_PROTO_L2_FAX: reqbuf->XBuffer.P[2] = 0x10; reqbuf->XBuffer.P[3] = 0; reqbuf->XBuffer.P[4] = 0; reqbuf->XBuffer.P[5] = 0; reqbuf->XBuffer.P[6] = 128; reqbuf->XBuffer.P[7] = 0; break; case ISDN_PROTO_L2_TRANS: switch(chan->l3prot) { case ISDN_PROTO_L3_TRANSDSP: reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */ } break; } reqbuf->XBuffer.P[8] = 0; reqbuf->XBuffer.length = l; reqbuf->Reference = 0; /* Sig Entity */ eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No); return(0);}intidi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer){ struct sk_buff *skb; struct sk_buff *skb2; eicon_REQ *reqbuf; eicon_chan_ptr *chan2; skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!skb) || (!skb2)) { eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No); if (skb) dev_kfree_skb(skb); if (skb2) dev_kfree_skb(skb2); return -ENOMEM; } chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig"); if (layer) cmd |= 0x700; switch(cmd) { case ASSIGN: case ASSIGN|0x700: idi_assign_req(reqbuf, layer, chan); break; case REMOVE: case REMOVE|0x700: idi_put_req(reqbuf, REMOVE, layer, 0); break; case INDICATE_REQ: idi_put_req(reqbuf, INDICATE_REQ, 0, 0); break; case HANGUP: idi_put_req(reqbuf, HANGUP, 0, 0); break; case SUSPEND: idi_put_suspend_req(reqbuf, chan); break; case RESUME: idi_put_req(reqbuf, RESUME, 0 ,0); break; case REJECT: idi_put_req(reqbuf, REJECT, 0 ,0); break; case CALL_ALERT: idi_put_req(reqbuf, CALL_ALERT, 0, 0); break; case CALL_RES: idi_call_res_req(reqbuf, chan); break; case CALL_HOLD: idi_put_req(reqbuf, CALL_HOLD, 0, 0); break; case N_CONNECT|0x700: idi_put_req(reqbuf, N_CONNECT, 1, 0); break; case N_CONNECT_ACK|0x700: idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0); break; case N_DISC|0x700: idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh); break; case N_DISC_ACK|0x700: idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); dev_kfree_skb(skb); dev_kfree_skb(skb2); return(-1); } skb_queue_tail(&chan->e.X, skb); skb_queue_tail(&card->sndq, skb2); eicon_schedule_tx(card); return(0);}inteicon_idi_listen_req(eicon_card *card, eicon_chan *chan){ if ((!card) || (!chan)) return 1; eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask); if (!chan->e.D3Id) { idi_do_req(card, chan, ASSIGN, 0); } if (chan->fsm_state == EICON_STATE_NULL) { if (!(chan->statectrl & HAVE_CONN_REQ)) { idi_do_req(card, chan, INDICATE_REQ, 0); chan->fsm_state = EICON_STATE_LISTEN; } } return(0);}unsigned charidi_si2bc(int si1, int si2, char *bc, char *hlc){ hlc[0] = 0; switch(si1) { case 1: bc[0] = 0x90; /* 3,1 kHz audio */ bc[1] = 0x90; /* 64 kbit/s */ bc[2] = 0xa3; /* G.711 A-law */#ifdef EICON_FULL_SERVICE_OKTETT if (si2 == 1) { bc[0] = 0x80; /* Speech */ hlc[0] = 0x02; /* hlc len */ hlc[1] = 0x91; /* first hic */ hlc[2] = 0x81; /* Telephony */ }#endif return(3); case 2: bc[0] = 0x90; /* 3,1 kHz audio */ bc[1] = 0x90; /* 64 kbit/s */ bc[2] = 0xa3; /* G.711 A-law */#ifdef EICON_FULL_SERVICE_OKTETT if (si2 == 2) { hlc[0] = 0x02; /* hlc len */ hlc[1] = 0x91; /* first hic */ hlc[2] = 0x84; /* Fax Gr.2/3 */ }#endif return(3); case 5: case 7: default: bc[0] = 0x88; bc[1] = 0x90; return(2); } return (0);}intidi_hangup(eicon_card *card, eicon_chan *chan){ if ((!card) || (!chan)) return 1; if ((chan->fsm_state == EICON_STATE_ACTIVE) || (chan->fsm_state == EICON_STATE_WMCONN)) { if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1); } if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); if (chan->fsm_state != EICON_STATE_NULL) { chan->statectrl |= WAITING_FOR_HANGUP; idi_do_req(card, chan, HANGUP, 0); chan->fsm_state = EICON_STATE_NULL; } eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);#ifdef CONFIG_ISDN_TTY_FAX chan->fax = 0;#endif return(0);}intcapipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm){ if ((cm->para[0] != 3) || (cm->para[1] != 0)) return -1; if (cm->para[2] < 3) return -1; if (cm->para[4] != 0) return -1; switch(cm->para[3]) { case 4: /* Suspend */ eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No); if (cm->para[5]) { idi_do_req(card, chan, SUSPEND, 0); } else { idi_do_req(card, chan, CALL_HOLD, 0); } break; case 5: /* Resume */ eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No); idi_do_req(card, chan, RESUME, 0); break; } return 0;}intidi_connect_res(eicon_card *card, eicon_chan *chan){ if ((!card) || (!chan)) return 1; chan->fsm_state = EICON_STATE_IWAIT; /* check if old NetID has been removed */ if (chan->e.B2Id) { eicon_log(card, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n", chan->No, chan->e.B2Id); idi_do_req(card, chan, REMOVE, 1); } idi_do_req(card, chan, ASSIGN, 1); idi_do_req(card, chan, CALL_RES, 0); return(0);}intidi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, char *eazmsn, int si1, int si2){ int l = 0; int i; unsigned char tmp; unsigned char *sub, *sp; unsigned char bc[5]; unsigned char hlc[5]; struct sk_buff *skb; struct sk_buff *skb2; eicon_REQ *reqbuf; eicon_chan_ptr *chan2; if ((!card) || (!chan)) return 1; skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); if ((!skb) || (!skb2)) { eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No); if (skb) dev_kfree_skb(skb); if (skb2) dev_kfree_skb(skb2); return -ENOMEM; } chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); chan2->ptr = chan; reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); reqbuf->Req = CALL_REQ; reqbuf->ReqCh = 0; reqbuf->ReqId = 1; sub = NULL; sp = phone; while (*sp) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -