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

📄 ipacx.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * * IPACX specific routines * * Author       Joerg Petersohn * Derived from hisax_isac.c, isac.c, hscx.c and others *  * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/kernel.h>#include <linux/config.h>#include <linux/init.h>#include "hisax_if.h"#include "hisax.h"#include "isdnl1.h"#include "ipacx.h"#define DBUSY_TIMER_VALUE 80#define TIMER3_VALUE      7000#define MAX_DFRAME_LEN_L1 300#define B_FIFO_SIZE       64#define D_FIFO_SIZE       32// ipacx interrupt mask values    #define _MASK_IMASK     0x2E  // global mask#define _MASKB_IMASK    0x0B#define _MASKD_IMASK    0x03  // all on//----------------------------------------------------------// local function declarations//----------------------------------------------------------static void ph_command(struct IsdnCardState *cs, unsigned int command);static inline void cic_int(struct IsdnCardState *cs);static void dch_l2l1(struct PStack *st, int pr, void *arg);static void dbusy_timer_handler(struct IsdnCardState *cs);static void dch_empty_fifo(struct IsdnCardState *cs, int count);static void dch_fill_fifo(struct IsdnCardState *cs);static inline void dch_int(struct IsdnCardState *cs);static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);static void __devinit dch_init(struct IsdnCardState *cs);static void bch_l2l1(struct PStack *st, int pr, void *arg);static void bch_empty_fifo(struct BCState *bcs, int count);static void bch_fill_fifo(struct BCState *bcs);static void bch_int(struct IsdnCardState *cs, u_char hscx);static void bch_mode(struct BCState *bcs, int mode, int bc);static void bch_close_state(struct BCState *bcs);static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);static int bch_setstack(struct PStack *st, struct BCState *bcs);static void __devinit bch_init(struct IsdnCardState *cs, int hscx);static void __init clear_pending_ints(struct IsdnCardState *cs);//----------------------------------------------------------// Issue Layer 1 command to chip//----------------------------------------------------------static void ph_command(struct IsdnCardState *cs, unsigned int command){	if (cs->debug &L1_DEB_ISAC)		debugl1(cs, "ph_command (%#x) in (%#x)", command,			cs->dc.isac.ph_state);//###################################  //	printk(KERN_INFO "ph_command (%#x)\n", command);//###################################  	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);}//----------------------------------------------------------// Transceiver interrupt handler//----------------------------------------------------------static inline void cic_int(struct IsdnCardState *cs){	u_char event;	event = cs->readisac(cs, IPACX_CIR0) >> 4;	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);//#########################################  //	printk(KERN_INFO "cic_int(%x)\n", event);//#########################################    cs->dc.isac.ph_state = event;  schedule_event(cs, D_L1STATECHANGE);}//==========================================================// D channel functions//==========================================================//----------------------------------------------------------// Command entry point//----------------------------------------------------------static voiddch_l2l1(struct PStack *st, int pr, void *arg){	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;	struct sk_buff *skb = arg;  u_char cda1_cr, cda2_cr;	switch (pr) {		case (PH_DATA |REQUEST):			if (cs->debug &DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);			if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);			if (cs->tx_skb) {				skb_queue_tail(&cs->sq, skb);#ifdef L2FRAME_DEBUG				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);#endif			} else {				cs->tx_skb = skb;				cs->tx_cnt = 0;#ifdef L2FRAME_DEBUG				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);#endif				dch_fill_fifo(cs);			}			break;      		case (PH_PULL |INDICATION):			if (cs->tx_skb) {				if (cs->debug & L1_DEB_WARN)					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");				skb_queue_tail(&cs->sq, skb);				break;			}			if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);			if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);			cs->tx_skb = skb;			cs->tx_cnt = 0;#ifdef L2FRAME_DEBUG			if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);#endif			dch_fill_fifo(cs);			break;      		case (PH_PULL | REQUEST):#ifdef L2FRAME_DEBUG			if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");#endif			if (!cs->tx_skb) {				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);			} else				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);			break;		case (HW_RESET | REQUEST):		case (HW_ENABLE | REQUEST):			if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||				(cs->dc.isac.ph_state == IPACX_IND_DR) ||				(cs->dc.isac.ph_state == IPACX_IND_DC))			        ph_command(cs, IPACX_CMD_TIM);			else				ph_command(cs, IPACX_CMD_RES);			break;		case (HW_INFO3 | REQUEST):			ph_command(cs, IPACX_CMD_AR8);			break;		case (HW_TESTLOOP | REQUEST):      cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1      cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1      cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);      cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);			if ((long)arg &1) { // loop B1        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a);       }      else {  // B1 off        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a);       }			if ((long)arg &2) { // loop B2        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14);       }      else {  // B2 off        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14);       }			break;		case (HW_DEACTIVATE | RESPONSE):			skb_queue_purge(&cs->rq);			skb_queue_purge(&cs->sq);			if (cs->tx_skb) {				dev_kfree_skb_any(cs->tx_skb);				cs->tx_skb = NULL;			}			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))				del_timer(&cs->dbusytimer);			break;		default:			if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);			break;	}}//----------------------------------------------------------//----------------------------------------------------------static voiddbusy_timer_handler(struct IsdnCardState *cs){	struct PStack *st;	int	rbchd, stard;	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {		rbchd = cs->readisac(cs, IPACX_RBCHD);		stard = cs->readisac(cs, IPACX_STARD);		if (cs->debug)       debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);		if (!(stard &0x40)) { // D-Channel Busy			set_bit(FLG_L1_DBUSY, &cs->HW_Flags);      for (st = cs->stlist; st; st = st->next) {				st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on			}		} else {			// seems we lost an interrupt; reset transceiver */			clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);			if (cs->tx_skb) {				dev_kfree_skb_any(cs->tx_skb);				cs->tx_cnt = 0;				cs->tx_skb = NULL;			} else {				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");				debugl1(cs, "D-Channel Busy no skb");			}			cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR		}	}}//----------------------------------------------------------// Fill buffer from receive FIFO//----------------------------------------------------------static void dch_empty_fifo(struct IsdnCardState *cs, int count){	u_char *ptr;	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))		debugl1(cs, "dch_empty_fifo()");  // message too large, remove	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {		if (cs->debug &L1_DEB_WARN)			debugl1(cs, "dch_empty_fifo() incoming message too large");	  cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC		cs->rcvidx = 0;		return;	}  	ptr = cs->rcvbuf + cs->rcvidx;	cs->rcvidx += count;  	cs->readisacfifo(cs, ptr, count);	cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC  	if (cs->debug &L1_DEB_ISAC_FIFO) {		char *t = cs->dlog;		t += sprintf(t, "dch_empty_fifo() cnt %d", count);		QuickHex(t, ptr, count);		debugl1(cs, cs->dlog);	}}//----------------------------------------------------------// Fill transmit FIFO//----------------------------------------------------------static void dch_fill_fifo(struct IsdnCardState *cs){	int count;	u_char cmd, *ptr;	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))		debugl1(cs, "dch_fill_fifo()");    	if (!cs->tx_skb) return;	count = cs->tx_skb->len;	if (count <= 0) return;	if (count > D_FIFO_SIZE) {		count = D_FIFO_SIZE;		cmd   = 0x08; // XTF	} else {		cmd   = 0x0A; // XTF | XME	}  	ptr = cs->tx_skb->data;	skb_pull(cs->tx_skb, count);	cs->tx_cnt += count;	cs->writeisacfifo(cs, ptr, count);	cs->writeisac(cs, IPACX_CMDRD, cmd);    // set timeout for transmission contol	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {		debugl1(cs, "dch_fill_fifo dbusytimer running");		del_timer(&cs->dbusytimer);	}	init_timer(&cs->dbusytimer);	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);	add_timer(&cs->dbusytimer);  	if (cs->debug &L1_DEB_ISAC_FIFO) {		char *t = cs->dlog;		t += sprintf(t, "dch_fill_fifo() cnt %d", count);		QuickHex(t, ptr, count);		debugl1(cs, cs->dlog);	}}//----------------------------------------------------------// D channel interrupt handler//----------------------------------------------------------static inline void dch_int(struct IsdnCardState *cs){	struct sk_buff *skb;	u_char istad, rstad;	int count;	istad = cs->readisac(cs, IPACX_ISTAD);//##############################################  //	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);//##############################################    	if (istad &0x80) {  // RME	  rstad = cs->readisac(cs, IPACX_RSTAD);		if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)			if (!(rstad &0x80))				if (cs->debug &L1_DEB_WARN)           debugl1(cs, "dch_int(): invalid frame");			if ((rstad &0x40))				if (cs->debug &L1_DEB_WARN)           debugl1(cs, "dch_int(): RDO");			if (!(rstad &0x20))				if (cs->debug &L1_DEB_WARN)           debugl1(cs, "dch_int(): CRC error");	    cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC		} else {  // received frame ok			count = cs->readisac(cs, IPACX_RBCLD);      if (count) count--; // RSTAB is last byte			count &= D_FIFO_SIZE-1;			if (count == 0) count = D_FIFO_SIZE;			dch_empty_fifo(cs, count);			if ((count = cs->rcvidx) > 0) {	      cs->rcvidx = 0;				if (!(skb = dev_alloc_skb(count)))					printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");				else {					memcpy(skb_put(skb, count), cs->rcvbuf, count);					skb_queue_tail(&cs->rq, skb);				}			}    }	  cs->rcvidx = 0;		schedule_event(cs, D_RCVBUFREADY);	}	if (istad &0x40) {  // RPF		dch_empty_fifo(cs, D_FIFO_SIZE);	}	if (istad &0x20) {  // RFO		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");	  cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES	}    if (istad &0x10) {  // XPR		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))			del_timer(&cs->dbusytimer);		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))			schedule_event(cs, D_CLEARBUSY);    if (cs->tx_skb) {      if (cs->tx_skb->len) {        dch_fill_fifo(cs);        goto afterXPR;      }      else {        dev_kfree_skb_irq(cs->tx_skb);        cs->tx_skb = NULL;        cs->tx_cnt = 0;      }    }    if ((cs->tx_skb = skb_dequeue(&cs->sq))) {      cs->tx_cnt = 0;      dch_fill_fifo(cs);    }     else {      schedule_event(cs, D_XMTBUFREADY);    }    }    afterXPR:	if (istad &0x0C) {  // XDU or XMR		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");	  if (cs->tx_skb) {	    skb_push(cs->tx_skb, cs->tx_cnt); // retransmit	    cs->tx_cnt = 0;			dch_fill_fifo(cs);		} else {			printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");			debugl1(cs, "ISAC XDU no skb");		}  }}//----------------------------------------------------------//----------------------------------------------------------static void __devinitdch_setstack(struct PStack *st, struct IsdnCardState *cs){	st->l1.l1hw = dch_l2l1;}//----------------------------------------------------------//----------------------------------------------------------static void __devinitdch_init(struct IsdnCardState *cs){	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");	cs->setstack_d      = dch_setstack;  	cs->dbusytimer.function = (void *) dbusy_timer_handler;	cs->dbusytimer.data = (long) cs;	init_timer(&cs->dbusytimer);  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel}//==========================================================// B channel functions//==========================================================//----------------------------------------------------------// Entry point for commands//----------------------------------------------------------static voidbch_l2l1(struct PStack *st, int pr, void *arg){	struct BCState *bcs = st->l1.bcs;	struct sk_buff *skb = arg;	u_long flags;	switch (pr) {		case (PH_DATA | REQUEST):			spin_lock_irqsave(&bcs->cs->lock, flags);			if (bcs->tx_skb) {				skb_queue_tail(&bcs->squeue, skb);			} else {				bcs->tx_skb = skb;

⌨️ 快捷键说明

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