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

📄 auerisdn_b.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *      auerisdn_b.c  --  Auerswald PBX/System Telephone ISDN B-channel 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>	/* ISDN constants */#include <linux/netdevice.h>	/* skb functions */#undef DEBUG			/* include debug macros until it's done */#include <linux/usb.h>		/* standard usb header */#include "auerisdn.h"#include "auermain.h"/*-------------------------------------------------------------------*//* ISDN B channel support defines                                    */#define AUISDN_BC_1MS		8	/* Bytes per channel and ms */#define AUISDN_BC_INC		4	/* change INT OUT size increment */#define AUISDN_BCDATATHRESHOLD	48	/* for unsymmetric 2-B-channels */#define AUISDN_TOGGLETIME	6	/* Timeout for unsymmetric serve *//*-------------------------------------------------------------------*//* 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/*-------------------------------------------------------------------*//* 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 B channel paket arrived, a B channel paket was sent)   c) from kernel daemon context (probe/disconnecting)*/void auerisdn_b_l1l2(struct auerisdnbc *bc, int pr, void *arg){	struct auerhisax *ahp;	struct sk_buff *skb;	/* do the callback */	ahp = bc->cp->isdn.ahp;	if (ahp) {		ahp->hisax_b_if[bc->channel].ifc.l1l2(&ahp->						      hisax_b_if[bc->								 channel].						      ifc, pr, arg);	} else {		dbg("auerisdn_b_l1l2 called without ahp");		if (pr == (PH_DATA | INDICATION)) {			skb = (struct sk_buff *) arg;			if (skb) {				skb_pull(skb, skb->len);				dev_kfree_skb_any(skb);			}		}	}}/* fill the INT OUT data buffer with new data *//* Transfer buffer size to fill is in urbp->transfer_buffer_length */static void auerisdn_bintbo_newdata(struct auerisdn *ip){	unsigned long flags;	struct urb *urbp = ip->intbo_urbp;	struct auerisdnbc *bc = &ip->bc[0];	/* start with B-channel 0 */	struct sk_buff *skb;	unsigned char *ucp;	int buf_size;	int len;	int bytes_sent;	int i;	/* FIXME: this algorithm is fixed to 2 B-channels */	/* Which B channel should we serve? */	if (ip->bc[1].mode != L1_MODE_NULL) {		/* B channel 1 is used */		if (bc->mode != L1_MODE_NULL) {			/* both B-channels are used */			if (ip->intbo_toggletimer) {				/* simply toggling */				ip->intbo_toggletimer--;				i = ip->intbo_index ^ 1;	/* serve both channels equal */			} else {				/* search the B channel with the most demand of data */				i = bc->txfree - ip->bc[1].txfree;				if (i < -AUISDN_BCDATATHRESHOLD)					i = 1;	/* B channel 1 needs more data */				else if (i > AUISDN_BCDATATHRESHOLD)					i = 0;	/* B channel 0 needs more data */				else					i = ip->intbo_index ^ 1;	/* serve both channels equal */				if (i == ip->intbo_index)					ip->intbo_toggletimer =					    AUISDN_TOGGLETIME;			}			bc = &ip->bc[i];			ip->intbo_index = i;		} else {			bc = &ip->bc[1];		}	}	dbg("INTBO: Fill B%d with %d Bytes, %d Bytes free",	    bc->channel + 1, urbp->transfer_buffer_length - AUH_SIZE,	    bc->txfree);	/* Fill the buffer with data */	ucp = ip->intbo_bufp;	*ucp++ = AUH_B1CHANNEL + bc->channel;	/* First byte is channel nr. */	buf_size = urbp->transfer_buffer_length - AUH_SIZE;	len = 0;	while (len < buf_size) {		spin_lock_irqsave(&bc->txskb_lock, flags);		if ((skb = bc->txskb)) {			/* dump ("raw tx data:", skb->data, skb->len); */			if (bc->mode == L1_MODE_TRANS) {				bytes_sent = buf_size - len;				if (skb->len < bytes_sent)					bytes_sent = skb->len;				{	/* swap tx bytes */					register unsigned char *src =					    skb->data;					unsigned int count;					for (count = 0; count < bytes_sent;					     count++)						*ucp++ =						    isdnhdlc_bit_rev_tab						    [*src++];				}				len += bytes_sent;				bc->lastbyte = skb->data[bytes_sent - 1];			} else {				int bs =				    isdnhdlc_encode(&bc->outp_hdlc_state,						    skb->data, skb->len,						    &bytes_sent,						    ucp, buf_size - len);				/* dump ("hdlc data:", ucp, bs); */				len += bs;				ucp += bs;			}			skb_pull(skb, bytes_sent);			if (!skb->len) {				// Frame sent				bc->txskb = NULL;				spin_unlock_irqrestore(&bc->txskb_lock,						       flags);				auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,						(void *) skb->truesize);				dev_kfree_skb_any(skb);				continue;	//while			}		} else {			if (bc->mode == L1_MODE_TRANS) {				memset(ucp, bc->lastbyte, buf_size - len);				ucp += buf_size - len;				len = buf_size;				/* dbg ("fill = 0xFF"); */			} else {				// Send flags				int bs =				    isdnhdlc_encode(&bc->outp_hdlc_state,						    NULL, 0, &bytes_sent,						    ucp, buf_size - len);				/* dbg ("fill = 0x%02X", (int)*ucp); */				len += bs;				ucp += bs;			}		}		spin_unlock_irqrestore(&bc->txskb_lock, flags);	}	/* dbg ("%d Bytes to TX buffer", len); */}/* INT OUT completion handler */static void auerisdn_bintbo_complete(struct urb *urbp){	struct auerisdn *ip = urbp->context;	/* unlink completion? */	if ((urbp->status == -ENOENT) || (urbp->status == -ECONNRESET)) {		/* should we restart with another size? */		if (ip->intbo_state == INTBOS_CHANGE) {			dbg("state => RESTART");			ip->intbo_state = INTBOS_RESTART;		} else {			/* set up variables for later restart */			dbg("INTBO stopped");			ip->intbo_state = INTBOS_IDLE;		}		/* nothing more to do */		return;	}	/* other state != 0? */	if (urbp->status) {		warn("auerisdn_bintbo_complete: status = %d",		     urbp->status);		return;	}	/* Should we fill in new data? */	if (ip->intbo_state == INTBOS_CHANGE) {		dbg("state == INTBOS_CHANGE, no new data");		return;	}	/* fill in new data */	auerisdn_bintbo_newdata(ip);}/* set up the INT OUT URB the first time *//* Don't start the URB */static void auerisdn_bintbo_setup(struct auerisdn *ip, unsigned int len){	ip->intbo_state = INTBOS_IDLE;	FILL_INT_URB(ip->intbo_urbp, ip->usbdev,		     usb_sndintpipe(ip->usbdev, ip->intbo_endp),		     ip->intbo_bufp, len, auerisdn_bintbo_complete, ip,		     ip->outInterval);	ip->intbo_urbp->transfer_flags |= USB_ASYNC_UNLINK;	ip->intbo_urbp->status = 0;}/* restart the INT OUT endpoint */static void auerisdn_bintbo_restart(struct auerisdn *ip){	struct urb *urbp = ip->intbo_urbp;	int status;	/* dbg ("auerisdn_intbo_restart"); */	/* fresh restart */	auerisdn_bintbo_setup(ip, ip->paketsize + AUH_SIZE);	/* Fill in new data */	auerisdn_bintbo_newdata(ip);	/* restart the urb */	ip->intbo_state = INTBOS_RUNNING;	status = usb_submit_urb(urbp);	if (status < 0) {		err("can't submit INT OUT urb, status = %d", status);		urbp->status = status;		urbp->complete(urbp);	}}/* change the size of the INT OUT endpoint */static void auerisdn_bchange(struct auerisdn *ip, unsigned int paketsize){	/* changing... */	dbg("txfree[0] = %d, txfree[1] = %d, old size = %d, new size = %d",	    ip->bc[0].txfree, ip->bc[1].txfree, ip->paketsize, paketsize);	ip->paketsize = paketsize;	if (paketsize == 0) {		/* stop the INT OUT endpoint */		dbg("stop unlinking INT out urb");		ip->intbo_state = INTBOS_IDLE;		usb_unlink_urb(ip->intbo_urbp);		return;	}	if (ip->intbo_state != INTBOS_IDLE) {		/* dbg ("unlinking INT out urb"); */		ip->intbo_state = INTBOS_CHANGE;		usb_unlink_urb(ip->intbo_urbp);	} else {		/* dbg ("restart immediately"); */		auerisdn_bintbo_restart(ip);	}}/* serve the outgoing B channel interrupt *//* Called from the INT IN completion handler */static void auerisdn_bserv(struct auerisdn *ip){	struct auerisdnbc *bc;	unsigned int u;	unsigned int paketsize;	/* should we start the INT OUT endpoint again? */	if (ip->intbo_state == INTBOS_RESTART) {		/* dbg ("Restart INT OUT from INT IN"); */		auerisdn_bintbo_restart(ip);		return;	}	/* no new calculation if change already in progress */	if (ip->intbo_state == INTBOS_CHANGE)		return;	/* calculation of transfer parameters for INT OUT endpoint */	paketsize = 0;	for (u = 0; u < AUISDN_BCHANNELS; u++) {		bc = &ip->bc[u];		if (bc->mode != L1_MODE_NULL) {	/* B channel is active */			unsigned int bpp = AUISDN_BC_1MS * ip->outInterval;			if (bc->txfree < bpp) {	/* buffer is full, throttle */				bc->txsize = bpp - AUISDN_BC_INC;				paketsize += bpp - AUISDN_BC_INC;			} else if (bc->txfree < bpp * 2) {				paketsize += bc->txsize;	/* schmidt-trigger, continue */			} else if (bc->txfree < bpp * 4) {	/* we are in synch */				bc->txsize = bpp;				paketsize += bpp;			} else if (bc->txfree > bc->ofsize / 2) {/* we have to fill the buffer */				bc->txsize = bpp + AUISDN_BC_INC;				paketsize += bpp + AUISDN_BC_INC;			} else {				paketsize += bc->txsize;	/* schmidt-trigger, continue */			}		}	}	/* check if we have to change the paket size */	if (paketsize != ip->paketsize)

⌨️ 快捷键说明

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