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

📄 auerisdn.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *      auerisdn.c  --  Auerswald PBX/System Telephone ISDN interface. * *      Copyright (C) 2002  Wolfgang M黣s (wolfgang@iksw-muees.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 of the License, 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/isdnif.h>#include <linux/netdevice.h>#include <linux/sched.h>#undef	DEBUG			/* include debug macros until it's done */#include <linux/usb.h>#include "auerisdn.h"#include "auermain.h"/*-------------------------------------------------------------------*//* ISDN support defines                                              */#define AUISDN_TEI	64	/* use a constant TEI *//*-------------------------------------------------------------------*//* Debug support 						     */#ifdef DEBUG#define dump( desc, adr, len) \do {			\	unsigned int u;	\	printk (KERN_DEBUG); \	printk (desc); \	for (u = 0; u < len; u++) \		printk (" %02X", adr[u] & 0xFF); \	printk ("\n"); \} while (0)#else#define dump( desc, adr, len)#endif/*-------------------------------------------------------------------*//* Hisax Interface.     					     *//* The interface to hisax is long-lasting because hisax_unregister()   don't work well in Linux 2.4.x. So we have to hold each registered   hisax interface until driver removal. */static struct auerhisax auerhisax_table[AUER_MAX_DEVICES];/*-------------------------------------------------------------------*//* Callback to L2 for HISAX *//* This callback can be called from 3 sources:   a) from hisax context (answer from a l2l1 function)   b) from interrupt context (a D channel paket arrived)   c) from kernel daemon context (probe/disconnecting)*/static void auerisdn_d_l1l2(struct auerisdn *ip, int pr, void *arg){	struct sk_buff *skb;	struct auerhisax *ahp;	/* do the callback */	ahp = ip->ahp;	if (ahp) {		ahp->hisax_d_if.ifc.l1l2(&ahp->hisax_d_if.ifc, pr, arg);	} else {		dbg("auerisdn_d_l1l2 with ahp == NULL");		if (pr == (PH_DATA | INDICATION)) {			skb = (struct sk_buff *) arg;			if (skb) {				skb_pull(skb, skb->len);				dev_kfree_skb_any(skb);			}		}	}}/* D-Channel sending completion function */static void auerisdn_dcw_complete(struct urb *urb){	struct auerbuf *bp = (struct auerbuf *) urb->context;	struct auerswald *cp =	    ((struct auerswald *) ((char *) (bp->list) -				   (unsigned				    long) (&((struct auerswald *) 0)->					   bufctl)));	dbg("auerisdn_dcw_complete with status %d", urb->status);	/* reuse the buffer */	auerbuf_releasebuf(bp);	/* Wake up all processes waiting for a buffer */	wake_up(&cp->bufferwait);}/* Translate non-ETSI ISDN messages from the device */static void auerisdn_translate_incoming(struct auerswald *cp,					unsigned char *msg,					unsigned int len){	struct auerbuf *bp;	int ret;	/* Translate incomming CONNECT -> CONNECT_ACK */	/* Format:   0   1    2     3     4        5        6    7      */	/*         SAPI TEI TXSEQ RXSEQ PID=08 CREFLEN=01 CREF MSG=7 ...*/	/* CREF.7 == 0 -> Incoming Call                                 */	/* Check for minimum length */	if (len < 8)		return;	/* Check for a CONNECT, call originated from device */	if (((msg[6] & 0x80) == 0) && (msg[7] == 0x07)) {		dbg("false CONNECT from device found");		/* change into CONNECT_ACK */		msg[7] = 0x0F;		/* Send a CONNECT_ACK back to the device */		/* get a new data buffer */		bp = auerbuf_getbuf(&cp->bufctl);		if (!bp) {			warn("no auerbuf free");			return;		}		/* Form a CONNECT ACK */		bp->bufp[0] =		    cp->isdn.dchannelservice.id | AUH_DIRECT | AUH_UNSPLIT;		bp->bufp[1] = 0x08;		bp->bufp[2] = 0x01;		bp->bufp[3] = msg[6] | 0x80;		bp->bufp[4] = 0x0F;		/* Set the transfer Parameters */		bp->len = 5;		bp->dr->bRequestType = AUT_WREQ;		bp->dr->bRequest = AUV_WBLOCK;		bp->dr->wValue = cpu_to_le16(0);		bp->dr->wIndex =		    cpu_to_le16(cp->isdn.dchannelservice.				id | AUH_DIRECT | AUH_UNSPLIT);		bp->dr->wLength = cpu_to_le16(5);		FILL_CONTROL_URB(bp->urbp, cp->usbdev,				 usb_sndctrlpipe(cp->usbdev, 0),				 (unsigned char *) bp->dr, bp->bufp, 5,				 auerisdn_dcw_complete, bp);		/* up we go */		ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);		if (ret)			auerisdn_dcw_complete(bp->urbp);		else			dbg("auerisdn_translate: Write OK");	}	/* Check for a DISCONNECT and change to RELEASE */	if (msg[7] == 0x45) {		dbg("DISCONNECT changed to RELEASE");		msg[7] = 0x4D;		return;	}}/* a D-channel paket arrived from the device */static void auerisdn_dispatch_dc(struct auerscon *scp, struct auerbuf *bp){	struct sk_buff *skb;	struct auerhisax *ahp;	struct auerswald *cp =	    ((struct auerswald *) ((char *) (scp) -				   (unsigned				    long) (&((struct auerswald *) 0)->isdn.					   dchannelservice)));	unsigned char *sp;	unsigned int l2_index;	unsigned char c;	unsigned char l2_header[10];	unsigned long flags;	dump("D-Channel paket arrived:", bp->bufp, bp->len);	if (cp->disconnecting)		return;	/* add a self-generated L2 message header */	l2_index = 0;	l2_header[l2_index++] = 0x02;	/* SAPI 0, C/R = 1 */	/* Parse the L3 message */	sp = bp->bufp + AUH_SIZE;	c = *sp++;		/* Protocol discriminator */	if (c != 0x08) {		warn("D channel paket is not ETSI");		return;	}	c = *sp++;		/* Call Reference length byte */	sp += c;		/* Skip Call Reference */	/* translate charge IEs */	/* Format of Auerswald Header:	   0x32 len=0x0B 0xFF 0xFF 0x73 len=0x07 0x27 */	/* Format of IE2_UNIT:	   0x49 len=0x04 uu1 uu2 uu3 uu4 */	/* Translate into: (?? Bytes)	   0x1C Facility	   0x?? restlen	   0x91 Sup. Services	   0xA1 Invoke	   0x?? restlen	   0x02 Invoke ID Tag	   0x02 Invoke ID len	   0x12 Invoke ID = 0x1234	   0x34	   0x02 OP Value Tag	   0x01 Length of OPvalue	   0x24 OpValue = AOCE	   0x30 Universal Constructor Sequence	   0x?? restlen	   0x30 Universal Constructor Sequence	   0x?? restlen	   0xA1 Context Specific Constructor Recorded Units List	   0x?? restlen	   0x30 Universal Constructor Sequence	   0x?? restlen	   0x02 Universal Primitive Integer	   0x?? len from IE2_UNIT	   uu1  Recorded Units List	   uu2	   uu3	   uu4	 */	{		unsigned char *ucp = sp;	// pointer to start of msg		int l = bp->len;	// length until EOP		unsigned char alen;	// length of auerswald msg		l -= (int) (ucp - bp->bufp);		// scan for Auerswald Header		for (; l >= 9; l--, ucp++) {	// 9 = minimal length of auerswald msg			if (ucp[0] != 0x32)				continue;			if (ucp[2] != 0xFF)				continue;			if (ucp[3] != 0xFF)				continue;			if (ucp[4] != 0x73)				continue;			if (ucp[6] != 0x27)				continue;			// Auerswald Header found. Is it units?			dbg("Auerswald msg header found");			alen = ucp[1] + 2;			if (ucp[7] == 0x49) {				// yes				unsigned char ul = ucp[8] + 1;	// length of charge integer				unsigned char charge[32];				// Copy charge info into new buffer				unsigned char *xp = &ucp[8];				int count;				for (count = 0; count < ul; count++)					charge[count] = *xp++;				// Erase auerswald msg				count = l - alen;				xp = ucp;				for (; count; count--, xp++)					xp[0] = xp[alen];				l -= alen;				bp->len -= alen;				// make room for new message				count = l;				xp = &ucp[l - 1];				for (; count; count--, xp--);				xp[21 + ul] = xp[0];				l += (21 + ul);				bp->len += (21 + ul);				// insert IE header				ucp[0] = 0x1C;				ucp[1] = 19 + ul;				ucp[2] = 0x91;				ucp[3] = 0xA1;				ucp[4] = 16 + ul;				ucp[5] = 0x02;				ucp[6] = 0x02;				ucp[7] = 0x12;				ucp[8] = 0x34;				ucp[9] = 0x02;				ucp[10] = 0x01;				ucp[11] = 0x24;				ucp[12] = 0x30;				ucp[13] = 7 + ul;				ucp[14] = 0x30;				ucp[15] = 5 + ul;				ucp[16] = 0xA1;				ucp[17] = 3 + ul;				ucp[18] = 0x30;				ucp[19] = 1 + ul;				ucp[20] = 0x02;				// Insert charge units				xp = &ucp[21];				for (count = 0; count < ul; count++)					*xp++ = charge[count];				dump("Rearranged message:", bp->bufp,				     bp->len);				break;			} else {				// we can't handle something else, erase it				int count = l - alen;				unsigned char *xp = ucp;				for (; count; count--, xp++)					xp[0] = xp[alen];				l -= alen;				bp->len -= alen;				dump("Shortened message:", bp->bufp,				     bp->len);			}		}	}	c = *sp;		/* Message type */	if (c == 0x05) {		/* SETUP. Use an UI frame */		dbg("SETUP");		l2_header[l2_index++] = 0xFF;	/* TEI 127 */		l2_header[l2_index++] = 0x03;	/* UI control field */		skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index);	} else {		/* use an I frame */		dbg("I Frame");		l2_header[l2_index++] = (AUISDN_TEI << 1) | 0x01;	/* TEI byte */		skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index + 2);		if (skb) {			ahp = cp->isdn.ahp;			if (!ahp) {				err("ahp == NULL");				return;			}			spin_lock_irqsave(&ahp->seq_lock, flags);			l2_header[l2_index++] = ahp->txseq;	/* transmitt sequence number */			l2_header[l2_index++] = ahp->rxseq;	/* receive sequence number */			ahp->txseq += 2;			/* next paket gets next number */			spin_unlock_irqrestore(&ahp->seq_lock, flags);		}	}	if (!skb) {		err("no memory - skipped");		return;	}	sp = skb_put(skb, bp->len - AUH_SIZE + l2_index);	/* Add L2 header */	memcpy(sp, l2_header, l2_index);	memcpy(sp + l2_index, bp->bufp + AUH_SIZE, bp->len - AUH_SIZE);	/* Translate false messages */	auerisdn_translate_incoming(cp, sp, bp->len - AUH_SIZE + l2_index);	/* Send message to L2 */	auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION, skb);}/* D-channel is closed because the device is removed *//* This is a no-op because ISDN close is handled different */static void auerisdn_disconnect_dc(struct auerscon *scp){}/* confirmation helper function. */static void auerisdn_d_confirmskb(struct auerswald *cp,				  struct sk_buff *skb){	/* free the skb */	if (skb) {		skb_pull(skb, skb->len);		dev_kfree_skb_any(skb);	}	/* confirm the sending of data */	dbg("Confirm PH_DATA");	auerisdn_d_l1l2(&cp->isdn, PH_DATA | CONFIRM, NULL);}/* D-channel transfer function L2->L1 */static void auerisdn_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg){	struct auerhisax *ahp;	struct sk_buff *skb;	unsigned int len;	int ret;	struct auerbuf *bp;	struct auerswald *cp;	unsigned long flags;	unsigned int l2_index;	unsigned char c;	unsigned char l2_header[32];	unsigned char *sp;	dbg("hisax D-Channel l2l1 called");	/* Get reference to auerhisax struct */	cp = NULL;	ahp = hisax_d_if->priv;	if (ahp)		cp = ahp->cp;	if (cp && !cp->disconnecting) {		/* normal usage */		switch (pr) {		case PH_ACTIVATE | REQUEST:	/* activation request */			dbg("Activation Request");			cp->isdn.dc_activated = 1;			/* send activation back to layer 2 */			auerisdn_d_l1l2(&cp->isdn,					PH_ACTIVATE | INDICATION, NULL);			break;		case PH_DEACTIVATE | REQUEST:	/* deactivation request */			dbg("Deactivation Request");			cp->isdn.dc_activated = 0;			/* send deactivation back to layer 2 */			auerisdn_d_l1l2(&cp->isdn,					PH_DEACTIVATE | INDICATION, NULL);			break;		case PH_DATA | REQUEST:	/* Transmit data request */			skb = (struct sk_buff *) arg;			len = skb->len;			l2_index = 0;			sp = skb->data;			dump("Data Request:", sp, len);			/* Parse the L2 header */			if (!len)				goto phd_free;			c = *sp++;	/* SAPI */			l2_header[l2_index++] = c;			len--;			if (!len)				goto phd_free;			c = *sp++;	/* TEI */			l2_header[l2_index++] = c;			len--;			if (!len)				goto phd_free;			c = *sp++;	/* Control Field, Byte 1 */			len--;			if (!(c & 0x01)) {				/* I FRAME */				dbg("I Frame");				if (!len)					goto phd_free;				spin_lock_irqsave(&ahp->seq_lock, flags);				ahp->rxseq = c + 2;	/* store new sequence info */				spin_unlock_irqrestore(&ahp->seq_lock,						       flags);				sp++;	/* skip Control Field, Byte 2 */				len--;				/* Check for RELEASE command */				/* and change to RELEASE_COMPLETE */				if (sp[3] == 0x4D)					sp[3] = 0x5A;				goto phd_send;			}			/* check the frame type */			switch (c) {			case 0x03:	/* UI frame */				dbg("UI Frame");				if (l2_header[0] == 0xFC) {					dbg("TEI Managment");					l2_header[0] = 0xFE;	/* set C/R bit in answer */					l2_header[l2_index++] = c;	/* Answer is UI frame */					if (!len)						break;					c = *sp++;	/* Managment ID */					len--;					if (c != 0x0F)						break;					l2_header[l2_index++] = c;					/* Read Reference Number */					if (!len)						break;					l2_header[l2_index++] = *sp++;					len--;					if (!len)						break;					l2_header[l2_index++] = *sp++;					len--;					if (!len)						break;					c = *sp++;	/* Message Type */					len--;					switch (c) {					case 0x01:	/* Identity Request */						dbg("Identity Request");						l2_header[l2_index++] = 0x02;	/* Identity Assign */						l2_header[l2_index++] =						    (AUISDN_TEI << 1) |						    0x01;						goto phd_answer;					default:						dbg("Unhandled TEI Managment %X", (int) c);						break;					}					// throw away					goto phd_free;				}				/* else send UI frame out */				goto phd_send;			case 0x01:	/* RR frame */			case 0x05:	/* RNR frame */				dbg("RR/RNR Frame");				if (!len)					break;				c = *sp++;	/* Control Field, Byte 2 */				len--;				if (!(c & 0x01))					break;	/* P/F = 1 in commands */				if (l2_header[0] & 0x02)					break;	/* C/R = 0 from TE */				dbg("Send RR as answer");				l2_header[l2_index++] = 0x01;	/* send an RR as Answer */				spin_lock_irqsave(&ahp->seq_lock, flags);				l2_header[l2_index++] = ahp->rxseq | 0x01;				spin_unlock_irqrestore(&ahp->seq_lock,						       flags);				goto phd_answer;			case 0x7F:	/* SABME */				dbg("SABME");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -