⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eicon_idi.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $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 + -