brintos

brintos / linux-shallow public Read only

0
0
Text · 42.3 KiB · d0b7271 Raw
1637 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * isac.c   ISAC specific routines4 *5 * Author       Karsten Keil <keil@isdn4linux.de>6 *7 * Copyright 2009  by Karsten Keil <keil@isdn4linux.de>8 */9 10#include <linux/irqreturn.h>11#include <linux/slab.h>12#include <linux/module.h>13#include <linux/mISDNhw.h>14#include "ipac.h"15 16 17#define DBUSY_TIMER_VALUE	8018#define ARCOFI_USE		119 20#define ISAC_REV		"2.0"21 22MODULE_AUTHOR("Karsten Keil");23MODULE_VERSION(ISAC_REV);24MODULE_DESCRIPTION("mISDN driver for ISAC specific functions");25MODULE_LICENSE("GPL v2");26 27#define ReadISAC(is, o)		(is->read_reg(is->dch.hw, o + is->off))28#define	WriteISAC(is, o, v)	(is->write_reg(is->dch.hw, o + is->off, v))29#define ReadHSCX(h, o)		(h->ip->read_reg(h->ip->hw, h->off + o))30#define WriteHSCX(h, o, v)	(h->ip->write_reg(h->ip->hw, h->off + o, v))31#define ReadIPAC(ip, o)		(ip->read_reg(ip->hw, o))32#define WriteIPAC(ip, o, v)	(ip->write_reg(ip->hw, o, v))33 34static inline void35ph_command(struct isac_hw *isac, u8 command)36{37	pr_debug("%s: ph_command %x\n", isac->name, command);38	if (isac->type & IPAC_TYPE_ISACX)39		WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);40	else41		WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);42}43 44static void45isac_ph_state_change(struct isac_hw *isac)46{47	switch (isac->state) {48	case (ISAC_IND_RS):49	case (ISAC_IND_EI):50		ph_command(isac, ISAC_CMD_DUI);51	}52	schedule_event(&isac->dch, FLG_PHCHANGE);53}54 55static void56isac_ph_state_bh(struct dchannel *dch)57{58	struct isac_hw *isac = container_of(dch, struct isac_hw, dch);59 60	switch (isac->state) {61	case ISAC_IND_RS:62	case ISAC_IND_EI:63		dch->state = 0;64		l1_event(dch->l1, HW_RESET_IND);65		break;66	case ISAC_IND_DID:67		dch->state = 3;68		l1_event(dch->l1, HW_DEACT_CNF);69		break;70	case ISAC_IND_DR:71	case ISAC_IND_DR6:72		dch->state = 3;73		l1_event(dch->l1, HW_DEACT_IND);74		break;75	case ISAC_IND_PU:76		dch->state = 4;77		l1_event(dch->l1, HW_POWERUP_IND);78		break;79	case ISAC_IND_RSY:80		if (dch->state <= 5) {81			dch->state = 5;82			l1_event(dch->l1, ANYSIGNAL);83		} else {84			dch->state = 8;85			l1_event(dch->l1, LOSTFRAMING);86		}87		break;88	case ISAC_IND_ARD:89		dch->state = 6;90		l1_event(dch->l1, INFO2);91		break;92	case ISAC_IND_AI8:93		dch->state = 7;94		l1_event(dch->l1, INFO4_P8);95		break;96	case ISAC_IND_AI10:97		dch->state = 7;98		l1_event(dch->l1, INFO4_P10);99		break;100	}101	pr_debug("%s: TE newstate %x\n", isac->name, dch->state);102}103 104static void105isac_empty_fifo(struct isac_hw *isac, int count)106{107	u8 *ptr;108 109	pr_debug("%s: %s  %d\n", isac->name, __func__, count);110 111	if (!isac->dch.rx_skb) {112		isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);113		if (!isac->dch.rx_skb) {114			pr_info("%s: D receive out of memory\n", isac->name);115			WriteISAC(isac, ISAC_CMDR, 0x80);116			return;117		}118	}119	if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {120		pr_debug("%s: %s overrun %d\n", isac->name, __func__,121			 isac->dch.rx_skb->len + count);122		WriteISAC(isac, ISAC_CMDR, 0x80);123		return;124	}125	ptr = skb_put(isac->dch.rx_skb, count);126	isac->read_fifo(isac->dch.hw, isac->off, ptr, count);127	WriteISAC(isac, ISAC_CMDR, 0x80);128	if (isac->dch.debug & DEBUG_HW_DFIFO) {129		char	pfx[MISDN_MAX_IDLEN + 16];130 131		snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",132			 isac->name, count);133		print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);134	}135}136 137static void138isac_fill_fifo(struct isac_hw *isac)139{140	int count, more;141	u8 *ptr;142 143	if (!isac->dch.tx_skb)144		return;145	count = isac->dch.tx_skb->len - isac->dch.tx_idx;146	if (count <= 0)147		return;148 149	more = 0;150	if (count > 32) {151		more = !0;152		count = 32;153	}154	pr_debug("%s: %s  %d\n", isac->name, __func__, count);155	ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;156	isac->dch.tx_idx += count;157	isac->write_fifo(isac->dch.hw, isac->off, ptr, count);158	WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);159	if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {160		pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);161		del_timer(&isac->dch.timer);162	}163	isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);164	add_timer(&isac->dch.timer);165	if (isac->dch.debug & DEBUG_HW_DFIFO) {166		char	pfx[MISDN_MAX_IDLEN + 16];167 168		snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",169			 isac->name, count);170		print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);171	}172}173 174static void175isac_rme_irq(struct isac_hw *isac)176{177	u8 val, count;178 179	val = ReadISAC(isac, ISAC_RSTA);180	if ((val & 0x70) != 0x20) {181		if (val & 0x40) {182			pr_debug("%s: ISAC RDO\n", isac->name);183#ifdef ERROR_STATISTIC184			isac->dch.err_rx++;185#endif186		}187		if (!(val & 0x20)) {188			pr_debug("%s: ISAC CRC error\n", isac->name);189#ifdef ERROR_STATISTIC190			isac->dch.err_crc++;191#endif192		}193		WriteISAC(isac, ISAC_CMDR, 0x80);194		dev_kfree_skb(isac->dch.rx_skb);195		isac->dch.rx_skb = NULL;196	} else {197		count = ReadISAC(isac, ISAC_RBCL) & 0x1f;198		if (count == 0)199			count = 32;200		isac_empty_fifo(isac, count);201		recv_Dchannel(&isac->dch);202	}203}204 205static void206isac_xpr_irq(struct isac_hw *isac)207{208	if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))209		del_timer(&isac->dch.timer);210	if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {211		isac_fill_fifo(isac);212	} else {213		dev_kfree_skb(isac->dch.tx_skb);214		if (get_next_dframe(&isac->dch))215			isac_fill_fifo(isac);216	}217}218 219static void220isac_retransmit(struct isac_hw *isac)221{222	if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))223		del_timer(&isac->dch.timer);224	if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {225		/* Restart frame */226		isac->dch.tx_idx = 0;227		isac_fill_fifo(isac);228	} else if (isac->dch.tx_skb) { /* should not happen */229		pr_info("%s: tx_skb exist but not busy\n", isac->name);230		test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);231		isac->dch.tx_idx = 0;232		isac_fill_fifo(isac);233	} else {234		pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);235		if (get_next_dframe(&isac->dch))236			isac_fill_fifo(isac);237	}238}239 240static void241isac_mos_irq(struct isac_hw *isac)242{243	u8 val;244	int ret;245 246	val = ReadISAC(isac, ISAC_MOSR);247	pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);248#if ARCOFI_USE249	if (val & 0x08) {250		if (!isac->mon_rx) {251			isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);252			if (!isac->mon_rx) {253				pr_info("%s: ISAC MON RX out of memory!\n",254					isac->name);255				isac->mocr &= 0xf0;256				isac->mocr |= 0x0a;257				WriteISAC(isac, ISAC_MOCR, isac->mocr);258				goto afterMONR0;259			} else260				isac->mon_rxp = 0;261		}262		if (isac->mon_rxp >= MAX_MON_FRAME) {263			isac->mocr &= 0xf0;264			isac->mocr |= 0x0a;265			WriteISAC(isac, ISAC_MOCR, isac->mocr);266			isac->mon_rxp = 0;267			pr_debug("%s: ISAC MON RX overflow!\n", isac->name);268			goto afterMONR0;269		}270		isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);271		pr_debug("%s: ISAC MOR0 %02x\n", isac->name,272			 isac->mon_rx[isac->mon_rxp - 1]);273		if (isac->mon_rxp == 1) {274			isac->mocr |= 0x04;275			WriteISAC(isac, ISAC_MOCR, isac->mocr);276		}277	}278afterMONR0:279	if (val & 0x80) {280		if (!isac->mon_rx) {281			isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);282			if (!isac->mon_rx) {283				pr_info("%s: ISAC MON RX out of memory!\n",284					isac->name);285				isac->mocr &= 0x0f;286				isac->mocr |= 0xa0;287				WriteISAC(isac, ISAC_MOCR, isac->mocr);288				goto afterMONR1;289			} else290				isac->mon_rxp = 0;291		}292		if (isac->mon_rxp >= MAX_MON_FRAME) {293			isac->mocr &= 0x0f;294			isac->mocr |= 0xa0;295			WriteISAC(isac, ISAC_MOCR, isac->mocr);296			isac->mon_rxp = 0;297			pr_debug("%s: ISAC MON RX overflow!\n", isac->name);298			goto afterMONR1;299		}300		isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);301		pr_debug("%s: ISAC MOR1 %02x\n", isac->name,302			 isac->mon_rx[isac->mon_rxp - 1]);303		isac->mocr |= 0x40;304		WriteISAC(isac, ISAC_MOCR, isac->mocr);305	}306afterMONR1:307	if (val & 0x04) {308		isac->mocr &= 0xf0;309		WriteISAC(isac, ISAC_MOCR, isac->mocr);310		isac->mocr |= 0x0a;311		WriteISAC(isac, ISAC_MOCR, isac->mocr);312		if (isac->monitor) {313			ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,314					    isac->mon_rx, isac->mon_rxp);315			if (ret)316				kfree(isac->mon_rx);317		} else {318			pr_info("%s: MONITOR 0 received %d but no user\n",319				isac->name, isac->mon_rxp);320			kfree(isac->mon_rx);321		}322		isac->mon_rx = NULL;323		isac->mon_rxp = 0;324	}325	if (val & 0x40) {326		isac->mocr &= 0x0f;327		WriteISAC(isac, ISAC_MOCR, isac->mocr);328		isac->mocr |= 0xa0;329		WriteISAC(isac, ISAC_MOCR, isac->mocr);330		if (isac->monitor) {331			ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,332					    isac->mon_rx, isac->mon_rxp);333			if (ret)334				kfree(isac->mon_rx);335		} else {336			pr_info("%s: MONITOR 1 received %d but no user\n",337				isac->name, isac->mon_rxp);338			kfree(isac->mon_rx);339		}340		isac->mon_rx = NULL;341		isac->mon_rxp = 0;342	}343	if (val & 0x02) {344		if ((!isac->mon_tx) || (isac->mon_txc &&345					(isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {346			isac->mocr &= 0xf0;347			WriteISAC(isac, ISAC_MOCR, isac->mocr);348			isac->mocr |= 0x0a;349			WriteISAC(isac, ISAC_MOCR, isac->mocr);350			if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {351				if (isac->monitor)352					isac->monitor(isac->dch.hw,353						      MONITOR_TX_0, NULL, 0);354			}355			kfree(isac->mon_tx);356			isac->mon_tx = NULL;357			isac->mon_txc = 0;358			isac->mon_txp = 0;359			goto AfterMOX0;360		}361		if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {362			if (isac->monitor)363				isac->monitor(isac->dch.hw,364					      MONITOR_TX_0, NULL, 0);365			kfree(isac->mon_tx);366			isac->mon_tx = NULL;367			isac->mon_txc = 0;368			isac->mon_txp = 0;369			goto AfterMOX0;370		}371		WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);372		pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,373			 isac->mon_tx[isac->mon_txp - 1]);374	}375AfterMOX0:376	if (val & 0x20) {377		if ((!isac->mon_tx) || (isac->mon_txc &&378					(isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {379			isac->mocr &= 0x0f;380			WriteISAC(isac, ISAC_MOCR, isac->mocr);381			isac->mocr |= 0xa0;382			WriteISAC(isac, ISAC_MOCR, isac->mocr);383			if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {384				if (isac->monitor)385					isac->monitor(isac->dch.hw,386						      MONITOR_TX_1, NULL, 0);387			}388			kfree(isac->mon_tx);389			isac->mon_tx = NULL;390			isac->mon_txc = 0;391			isac->mon_txp = 0;392			goto AfterMOX1;393		}394		if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {395			if (isac->monitor)396				isac->monitor(isac->dch.hw,397					      MONITOR_TX_1, NULL, 0);398			kfree(isac->mon_tx);399			isac->mon_tx = NULL;400			isac->mon_txc = 0;401			isac->mon_txp = 0;402			goto AfterMOX1;403		}404		WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);405		pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,406			 isac->mon_tx[isac->mon_txp - 1]);407	}408AfterMOX1:409	val = 0; /* dummy to avoid warning */410#endif411}412 413static void414isac_cisq_irq(struct isac_hw *isac) {415	u8 val;416 417	val = ReadISAC(isac, ISAC_CIR0);418	pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);419	if (val & 2) {420		pr_debug("%s: ph_state change %x->%x\n", isac->name,421			 isac->state, (val >> 2) & 0xf);422		isac->state = (val >> 2) & 0xf;423		isac_ph_state_change(isac);424	}425	if (val & 1) {426		val = ReadISAC(isac, ISAC_CIR1);427		pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);428	}429}430 431static void432isacsx_cic_irq(struct isac_hw *isac)433{434	u8 val;435 436	val = ReadISAC(isac, ISACX_CIR0);437	pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);438	if (val & ISACX_CIR0_CIC0) {439		pr_debug("%s: ph_state change %x->%x\n", isac->name,440			 isac->state, val >> 4);441		isac->state = val >> 4;442		isac_ph_state_change(isac);443	}444}445 446static void447isacsx_rme_irq(struct isac_hw *isac)448{449	int count;450	u8 val;451 452	val = ReadISAC(isac, ISACX_RSTAD);453	if ((val & (ISACX_RSTAD_VFR |454		    ISACX_RSTAD_RDO |455		    ISACX_RSTAD_CRC |456		    ISACX_RSTAD_RAB))457	    != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {458		pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);459#ifdef ERROR_STATISTIC460		if (val & ISACX_RSTAD_CRC)461			isac->dch.err_rx++;462		else463			isac->dch.err_crc++;464#endif465		WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);466		dev_kfree_skb(isac->dch.rx_skb);467		isac->dch.rx_skb = NULL;468	} else {469		count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;470		if (count == 0)471			count = 32;472		isac_empty_fifo(isac, count);473		if (isac->dch.rx_skb) {474			skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);475			pr_debug("%s: dchannel received %d\n", isac->name,476				 isac->dch.rx_skb->len);477			recv_Dchannel(&isac->dch);478		}479	}480}481 482irqreturn_t483mISDNisac_irq(struct isac_hw *isac, u8 val)484{485	if (unlikely(!val))486		return IRQ_NONE;487	pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);488	if (isac->type & IPAC_TYPE_ISACX) {489		if (val & ISACX__CIC)490			isacsx_cic_irq(isac);491		if (val & ISACX__ICD) {492			val = ReadISAC(isac, ISACX_ISTAD);493			pr_debug("%s: ISTAD %02x\n", isac->name, val);494			if (val & ISACX_D_XDU) {495				pr_debug("%s: ISAC XDU\n", isac->name);496#ifdef ERROR_STATISTIC497				isac->dch.err_tx++;498#endif499				isac_retransmit(isac);500			}501			if (val & ISACX_D_XMR) {502				pr_debug("%s: ISAC XMR\n", isac->name);503#ifdef ERROR_STATISTIC504				isac->dch.err_tx++;505#endif506				isac_retransmit(isac);507			}508			if (val & ISACX_D_XPR)509				isac_xpr_irq(isac);510			if (val & ISACX_D_RFO) {511				pr_debug("%s: ISAC RFO\n", isac->name);512				WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);513			}514			if (val & ISACX_D_RME)515				isacsx_rme_irq(isac);516			if (val & ISACX_D_RPF)517				isac_empty_fifo(isac, 0x20);518		}519	} else {520		if (val & 0x80)	/* RME */521			isac_rme_irq(isac);522		if (val & 0x40)	/* RPF */523			isac_empty_fifo(isac, 32);524		if (val & 0x10)	/* XPR */525			isac_xpr_irq(isac);526		if (val & 0x04)	/* CISQ */527			isac_cisq_irq(isac);528		if (val & 0x20)	/* RSC - never */529			pr_debug("%s: ISAC RSC interrupt\n", isac->name);530		if (val & 0x02)	/* SIN - never */531			pr_debug("%s: ISAC SIN interrupt\n", isac->name);532		if (val & 0x01) {	/* EXI */533			val = ReadISAC(isac, ISAC_EXIR);534			pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);535			if (val & 0x80)	/* XMR */536				pr_debug("%s: ISAC XMR\n", isac->name);537			if (val & 0x40) { /* XDU */538				pr_debug("%s: ISAC XDU\n", isac->name);539#ifdef ERROR_STATISTIC540				isac->dch.err_tx++;541#endif542				isac_retransmit(isac);543			}544			if (val & 0x04)	/* MOS */545				isac_mos_irq(isac);546		}547	}548	return IRQ_HANDLED;549}550EXPORT_SYMBOL(mISDNisac_irq);551 552static int553isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)554{555	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);556	struct dchannel		*dch = container_of(dev, struct dchannel, dev);557	struct isac_hw		*isac = container_of(dch, struct isac_hw, dch);558	int			ret = -EINVAL;559	struct mISDNhead	*hh = mISDN_HEAD_P(skb);560	u32			id;561	u_long			flags;562 563	switch (hh->prim) {564	case PH_DATA_REQ:565		spin_lock_irqsave(isac->hwlock, flags);566		ret = dchannel_senddata(dch, skb);567		if (ret > 0) { /* direct TX */568			id = hh->id; /* skb can be freed */569			isac_fill_fifo(isac);570			ret = 0;571			spin_unlock_irqrestore(isac->hwlock, flags);572			queue_ch_frame(ch, PH_DATA_CNF, id, NULL);573		} else574			spin_unlock_irqrestore(isac->hwlock, flags);575		return ret;576	case PH_ACTIVATE_REQ:577		ret = l1_event(dch->l1, hh->prim);578		break;579	case PH_DEACTIVATE_REQ:580		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);581		ret = l1_event(dch->l1, hh->prim);582		break;583	}584 585	if (!ret)586		dev_kfree_skb(skb);587	return ret;588}589 590static int591isac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para)592{593	u8 tl = 0;594	unsigned long flags;595	int ret = 0;596 597	switch (cmd) {598	case HW_TESTLOOP:599		spin_lock_irqsave(isac->hwlock, flags);600		if (!(isac->type & IPAC_TYPE_ISACX)) {601			/* TODO: implement for IPAC_TYPE_ISACX */602			if (para & 1) /* B1 */603				tl |= 0x0c;604			else if (para & 2) /* B2 */605				tl |= 0x3;606			/* we only support IOM2 mode */607			WriteISAC(isac, ISAC_SPCR, tl);608			if (tl)609				WriteISAC(isac, ISAC_ADF1, 0x8);610			else611				WriteISAC(isac, ISAC_ADF1, 0x0);612		}613		spin_unlock_irqrestore(isac->hwlock, flags);614		break;615	case HW_TIMER3_VALUE:616		ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff));617		break;618	default:619		pr_debug("%s: %s unknown command %x %lx\n", isac->name,620			 __func__, cmd, para);621		ret = -1;622	}623	return ret;624}625 626static int627isac_l1cmd(struct dchannel *dch, u32 cmd)628{629	struct isac_hw *isac = container_of(dch, struct isac_hw, dch);630	u_long flags;631 632	pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);633	switch (cmd) {634	case INFO3_P8:635		spin_lock_irqsave(isac->hwlock, flags);636		ph_command(isac, ISAC_CMD_AR8);637		spin_unlock_irqrestore(isac->hwlock, flags);638		break;639	case INFO3_P10:640		spin_lock_irqsave(isac->hwlock, flags);641		ph_command(isac, ISAC_CMD_AR10);642		spin_unlock_irqrestore(isac->hwlock, flags);643		break;644	case HW_RESET_REQ:645		spin_lock_irqsave(isac->hwlock, flags);646		if ((isac->state == ISAC_IND_EI) ||647		    (isac->state == ISAC_IND_DR) ||648		    (isac->state == ISAC_IND_DR6) ||649		    (isac->state == ISAC_IND_RS))650			ph_command(isac, ISAC_CMD_TIM);651		else652			ph_command(isac, ISAC_CMD_RS);653		spin_unlock_irqrestore(isac->hwlock, flags);654		break;655	case HW_DEACT_REQ:656		skb_queue_purge(&dch->squeue);657		if (dch->tx_skb) {658			dev_kfree_skb(dch->tx_skb);659			dch->tx_skb = NULL;660		}661		dch->tx_idx = 0;662		if (dch->rx_skb) {663			dev_kfree_skb(dch->rx_skb);664			dch->rx_skb = NULL;665		}666		test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);667		if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))668			del_timer(&dch->timer);669		break;670	case HW_POWERUP_REQ:671		spin_lock_irqsave(isac->hwlock, flags);672		ph_command(isac, ISAC_CMD_TIM);673		spin_unlock_irqrestore(isac->hwlock, flags);674		break;675	case PH_ACTIVATE_IND:676		test_and_set_bit(FLG_ACTIVE, &dch->Flags);677		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,678			    GFP_ATOMIC);679		break;680	case PH_DEACTIVATE_IND:681		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);682		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,683			    GFP_ATOMIC);684		break;685	default:686		pr_debug("%s: %s unknown command %x\n", isac->name,687			 __func__, cmd);688		return -1;689	}690	return 0;691}692 693static void694isac_release(struct isac_hw *isac)695{696	if (isac->type & IPAC_TYPE_ISACX)697		WriteISAC(isac, ISACX_MASK, 0xff);698	else if (isac->type != 0)699		WriteISAC(isac, ISAC_MASK, 0xff);700	if (isac->dch.timer.function != NULL) {701		del_timer(&isac->dch.timer);702		isac->dch.timer.function = NULL;703	}704	kfree(isac->mon_rx);705	isac->mon_rx = NULL;706	kfree(isac->mon_tx);707	isac->mon_tx = NULL;708	if (isac->dch.l1)709		l1_event(isac->dch.l1, CLOSE_CHANNEL);710	mISDN_freedchannel(&isac->dch);711}712 713static void714dbusy_timer_handler(struct timer_list *t)715{716	struct isac_hw *isac = from_timer(isac, t, dch.timer);717	int rbch, star;718	u_long flags;719 720	if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {721		spin_lock_irqsave(isac->hwlock, flags);722		rbch = ReadISAC(isac, ISAC_RBCH);723		star = ReadISAC(isac, ISAC_STAR);724		pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",725			 isac->name, rbch, star);726		if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */727			test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);728		else {729			/* discard frame; reset transceiver */730			test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);731			if (isac->dch.tx_idx)732				isac->dch.tx_idx = 0;733			else734				pr_info("%s: ISAC D-Channel Busy no tx_idx\n",735					isac->name);736			/* Transmitter reset */737			WriteISAC(isac, ISAC_CMDR, 0x01);738		}739		spin_unlock_irqrestore(isac->hwlock, flags);740	}741}742 743static int744open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller)745{746	pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,747		 isac->dch.dev.id, caller);748	if (rq->protocol != ISDN_P_TE_S0)749		return -EINVAL;750	if (rq->adr.channel == 1)751		/* E-Channel not supported */752		return -EINVAL;753	rq->ch = &isac->dch.dev.D;754	rq->ch->protocol = rq->protocol;755	if (isac->dch.state == 7)756		_queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,757			    0, NULL, GFP_KERNEL);758	return 0;759}760 761static int762open_dchannel(struct isac_hw *isac, struct channel_req *rq)763{764	return open_dchannel_caller(isac, rq, __builtin_return_address(0));765}766 767static const char *ISACVer[] =768{"2086/2186 V1.1", "2085 B1", "2085 B2",769 "2085 V2.3"};770 771static int772isac_init(struct isac_hw *isac)773{774	u8 val;775	int err = 0;776 777	if (!isac->dch.l1) {778		err = create_l1(&isac->dch, isac_l1cmd);779		if (err)780			return err;781	}782	isac->mon_tx = NULL;783	isac->mon_rx = NULL;784	timer_setup(&isac->dch.timer, dbusy_timer_handler, 0);785	isac->mocr = 0xaa;786	if (isac->type & IPAC_TYPE_ISACX) {787		/* Disable all IRQ */788		WriteISAC(isac, ISACX_MASK, 0xff);789		val = ReadISAC(isac, ISACX_STARD);790		pr_debug("%s: ISACX STARD %x\n", isac->name, val);791		val = ReadISAC(isac, ISACX_ISTAD);792		pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);793		val = ReadISAC(isac, ISACX_ISTA);794		pr_debug("%s: ISACX ISTA %x\n", isac->name, val);795		/* clear LDD */796		WriteISAC(isac, ISACX_TR_CONF0, 0x00);797		/* enable transmitter */798		WriteISAC(isac, ISACX_TR_CONF2, 0x00);799		/* transparent mode 0, RAC, stop/go */800		WriteISAC(isac, ISACX_MODED, 0xc9);801		/* all HDLC IRQ unmasked */802		val = ReadISAC(isac, ISACX_ID);803		if (isac->dch.debug & DEBUG_HW)804			pr_notice("%s: ISACX Design ID %x\n",805				  isac->name, val & 0x3f);806		val = ReadISAC(isac, ISACX_CIR0);807		pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);808		isac->state = val >> 4;809		isac_ph_state_change(isac);810		ph_command(isac, ISAC_CMD_RS);811		WriteISAC(isac, ISACX_MASK, IPACX__ON);812		WriteISAC(isac, ISACX_MASKD, 0x00);813	} else { /* old isac */814		WriteISAC(isac, ISAC_MASK, 0xff);815		val = ReadISAC(isac, ISAC_STAR);816		pr_debug("%s: ISAC STAR %x\n", isac->name, val);817		val = ReadISAC(isac, ISAC_MODE);818		pr_debug("%s: ISAC MODE %x\n", isac->name, val);819		val = ReadISAC(isac, ISAC_ADF2);820		pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);821		val = ReadISAC(isac, ISAC_ISTA);822		pr_debug("%s: ISAC ISTA %x\n", isac->name, val);823		if (val & 0x01) {824			val = ReadISAC(isac, ISAC_EXIR);825			pr_debug("%s: ISAC EXIR %x\n", isac->name, val);826		}827		val = ReadISAC(isac, ISAC_RBCH);828		if (isac->dch.debug & DEBUG_HW)829			pr_notice("%s: ISAC version (%x): %s\n", isac->name,830				  val, ISACVer[(val >> 5) & 3]);831		isac->type |= ((val >> 5) & 3);832		if (!isac->adf2)833			isac->adf2 = 0x80;834		if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */835			pr_info("%s: only support IOM2 mode but adf2=%02x\n",836				isac->name, isac->adf2);837			isac_release(isac);838			return -EINVAL;839		}840		WriteISAC(isac, ISAC_ADF2, isac->adf2);841		WriteISAC(isac, ISAC_SQXR, 0x2f);842		WriteISAC(isac, ISAC_SPCR, 0x00);843		WriteISAC(isac, ISAC_STCR, 0x70);844		WriteISAC(isac, ISAC_MODE, 0xc9);845		WriteISAC(isac, ISAC_TIMR, 0x00);846		WriteISAC(isac, ISAC_ADF1, 0x00);847		val = ReadISAC(isac, ISAC_CIR0);848		pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);849		isac->state = (val >> 2) & 0xf;850		isac_ph_state_change(isac);851		ph_command(isac, ISAC_CMD_RS);852		WriteISAC(isac, ISAC_MASK, 0);853	}854	return err;855}856 857int858mISDNisac_init(struct isac_hw *isac, void *hw)859{860	mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);861	isac->dch.hw = hw;862	isac->dch.dev.D.send = isac_l1hw;863	isac->init = isac_init;864	isac->release = isac_release;865	isac->ctrl = isac_ctrl;866	isac->open = open_dchannel;867	isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);868	isac->dch.dev.nrbchan = 2;869	return 0;870}871EXPORT_SYMBOL(mISDNisac_init);872 873static void874waitforCEC(struct hscx_hw *hx)875{876	u8 starb, to = 50;877 878	while (to) {879		starb = ReadHSCX(hx, IPAC_STARB);880		if (!(starb & 0x04))881			break;882		udelay(1);883		to--;884	}885	if (to < 50)886		pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,887			 50 - to);888	if (!to)889		pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);890}891 892 893static void894waitforXFW(struct hscx_hw *hx)895{896	u8 starb, to = 50;897 898	while (to) {899		starb = ReadHSCX(hx, IPAC_STARB);900		if ((starb & 0x44) == 0x40)901			break;902		udelay(1);903		to--;904	}905	if (to < 50)906		pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,907			 50 - to);908	if (!to)909		pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);910}911 912static void913hscx_cmdr(struct hscx_hw *hx, u8 cmd)914{915	if (hx->ip->type & IPAC_TYPE_IPACX)916		WriteHSCX(hx, IPACX_CMDRB, cmd);917	else {918		waitforCEC(hx);919		WriteHSCX(hx, IPAC_CMDRB, cmd);920	}921}922 923static void924hscx_empty_fifo(struct hscx_hw *hscx, u8 count)925{926	u8 *p;927	int maxlen;928 929	pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);930	if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) {931		hscx->bch.dropcnt += count;932		hscx_cmdr(hscx, 0x80); /* RMC */933		return;934	}935	maxlen = bchannel_get_rxbuf(&hscx->bch, count);936	if (maxlen < 0) {937		hscx_cmdr(hscx, 0x80); /* RMC */938		if (hscx->bch.rx_skb)939			skb_trim(hscx->bch.rx_skb, 0);940		pr_warn("%s.B%d: No bufferspace for %d bytes\n",941			hscx->ip->name, hscx->bch.nr, count);942		return;943	}944	p = skb_put(hscx->bch.rx_skb, count);945 946	if (hscx->ip->type & IPAC_TYPE_IPACX)947		hscx->ip->read_fifo(hscx->ip->hw,948				    hscx->off + IPACX_RFIFOB, p, count);949	else950		hscx->ip->read_fifo(hscx->ip->hw,951				    hscx->off, p, count);952 953	hscx_cmdr(hscx, 0x80); /* RMC */954 955	if (hscx->bch.debug & DEBUG_HW_BFIFO) {956		snprintf(hscx->log, 64, "B%1d-recv %s %d ",957			 hscx->bch.nr, hscx->ip->name, count);958		print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);959	}960}961 962static void963hscx_fill_fifo(struct hscx_hw *hscx)964{965	int count, more;966	u8 *p;967 968	if (!hscx->bch.tx_skb) {969		if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags))970			return;971		count = hscx->fifo_size;972		more = 1;973		p = hscx->log;974		memset(p, hscx->bch.fill[0], count);975	} else {976		count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;977		if (count <= 0)978			return;979		p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;980 981		more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;982		if (count > hscx->fifo_size) {983			count = hscx->fifo_size;984			more = 1;985		}986		pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr,987			 count, hscx->bch.tx_idx, hscx->bch.tx_skb->len);988		hscx->bch.tx_idx += count;989	}990	if (hscx->ip->type & IPAC_TYPE_IPACX)991		hscx->ip->write_fifo(hscx->ip->hw,992				     hscx->off + IPACX_XFIFOB, p, count);993	else {994		waitforXFW(hscx);995		hscx->ip->write_fifo(hscx->ip->hw,996				     hscx->off, p, count);997	}998	hscx_cmdr(hscx, more ? 0x08 : 0x0a);999 1000	if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) {1001		snprintf(hscx->log, 64, "B%1d-send %s %d ",1002			 hscx->bch.nr, hscx->ip->name, count);1003		print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);1004	}1005}1006 1007static void1008hscx_xpr(struct hscx_hw *hx)1009{1010	if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) {1011		hscx_fill_fifo(hx);1012	} else {1013		dev_kfree_skb(hx->bch.tx_skb);1014		if (get_next_bframe(&hx->bch)) {1015			hscx_fill_fifo(hx);1016			test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags);1017		} else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) {1018			hscx_fill_fifo(hx);1019		}1020	}1021}1022 1023static void1024ipac_rme(struct hscx_hw *hx)1025{1026	int count;1027	u8 rstab;1028 1029	if (hx->ip->type & IPAC_TYPE_IPACX)1030		rstab = ReadHSCX(hx, IPACX_RSTAB);1031	else1032		rstab = ReadHSCX(hx, IPAC_RSTAB);1033	pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);1034	if ((rstab & 0xf0) != 0xa0) {1035		/* !(VFR && !RDO && CRC && !RAB) */1036		if (!(rstab & 0x80)) {1037			if (hx->bch.debug & DEBUG_HW_BCHANNEL)1038				pr_notice("%s: B%1d invalid frame\n",1039					  hx->ip->name, hx->bch.nr);1040		}1041		if (rstab & 0x40) {1042			if (hx->bch.debug & DEBUG_HW_BCHANNEL)1043				pr_notice("%s: B%1d RDO proto=%x\n",1044					  hx->ip->name, hx->bch.nr,1045					  hx->bch.state);1046		}1047		if (!(rstab & 0x20)) {1048			if (hx->bch.debug & DEBUG_HW_BCHANNEL)1049				pr_notice("%s: B%1d CRC error\n",1050					  hx->ip->name, hx->bch.nr);1051		}1052		hscx_cmdr(hx, 0x80); /* Do RMC */1053		return;1054	}1055	if (hx->ip->type & IPAC_TYPE_IPACX)1056		count = ReadHSCX(hx, IPACX_RBCLB);1057	else1058		count = ReadHSCX(hx, IPAC_RBCLB);1059	count &= (hx->fifo_size - 1);1060	if (count == 0)1061		count = hx->fifo_size;1062	hscx_empty_fifo(hx, count);1063	if (!hx->bch.rx_skb)1064		return;1065	if (hx->bch.rx_skb->len < 2) {1066		pr_debug("%s: B%1d frame too short %d\n",1067			 hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);1068		skb_trim(hx->bch.rx_skb, 0);1069	} else {1070		skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);1071		recv_Bchannel(&hx->bch, 0, false);1072	}1073}1074 1075static void1076ipac_irq(struct hscx_hw *hx, u8 ista)1077{1078	u8 istab, m, exirb = 0;1079 1080	if (hx->ip->type & IPAC_TYPE_IPACX)1081		istab = ReadHSCX(hx, IPACX_ISTAB);1082	else if (hx->ip->type & IPAC_TYPE_IPAC) {1083		istab = ReadHSCX(hx, IPAC_ISTAB);1084		m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;1085		if (m & ista) {1086			exirb = ReadHSCX(hx, IPAC_EXIRB);1087			pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1088				 hx->bch.nr, exirb);1089		}1090	} else if (hx->bch.nr & 2) { /* HSCX B */1091		if (ista & (HSCX__EXA | HSCX__ICA))1092			ipac_irq(&hx->ip->hscx[0], ista);1093		if (ista & HSCX__EXB) {1094			exirb = ReadHSCX(hx, IPAC_EXIRB);1095			pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1096				 hx->bch.nr, exirb);1097		}1098		istab = ista & 0xF8;1099	} else { /* HSCX A */1100		istab = ReadHSCX(hx, IPAC_ISTAB);1101		if (ista & HSCX__EXA) {1102			exirb = ReadHSCX(hx, IPAC_EXIRB);1103			pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1104				 hx->bch.nr, exirb);1105		}1106		istab = istab & 0xF8;1107	}1108	if (exirb & IPAC_B_XDU)1109		istab |= IPACX_B_XDU;1110	if (exirb & IPAC_B_RFO)1111		istab |= IPACX_B_RFO;1112	pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);1113 1114	if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))1115		return;1116 1117	if (istab & IPACX_B_RME)1118		ipac_rme(hx);1119 1120	if (istab & IPACX_B_RPF) {1121		hscx_empty_fifo(hx, hx->fifo_size);1122		if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))1123			recv_Bchannel(&hx->bch, 0, false);1124	}1125 1126	if (istab & IPACX_B_RFO) {1127		pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);1128		hscx_cmdr(hx, 0x40);	/* RRES */1129	}1130 1131	if (istab & IPACX_B_XPR)1132		hscx_xpr(hx);1133 1134	if (istab & IPACX_B_XDU) {1135		if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {1136			if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags))1137				test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags);1138			hscx_xpr(hx);1139			return;1140		}1141		pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,1142			 hx->bch.nr, hx->bch.tx_idx);1143		hx->bch.tx_idx = 0;1144		hscx_cmdr(hx, 0x01);	/* XRES */1145	}1146}1147 1148irqreturn_t1149mISDNipac_irq(struct ipac_hw *ipac, int maxloop)1150{1151	int cnt = maxloop + 1;1152	u8 ista, istad;1153	struct isac_hw  *isac = &ipac->isac;1154 1155	if (ipac->type & IPAC_TYPE_IPACX) {1156		ista = ReadIPAC(ipac, ISACX_ISTA);1157		while (ista && --cnt) {1158			pr_debug("%s: ISTA %02x\n", ipac->name, ista);1159			if (ista & IPACX__ICA)1160				ipac_irq(&ipac->hscx[0], ista);1161			if (ista & IPACX__ICB)1162				ipac_irq(&ipac->hscx[1], ista);1163			if (ista & (ISACX__ICD | ISACX__CIC))1164				mISDNisac_irq(&ipac->isac, ista);1165			ista = ReadIPAC(ipac, ISACX_ISTA);1166		}1167	} else if (ipac->type & IPAC_TYPE_IPAC) {1168		ista = ReadIPAC(ipac, IPAC_ISTA);1169		while (ista && --cnt) {1170			pr_debug("%s: ISTA %02x\n", ipac->name, ista);1171			if (ista & (IPAC__ICD | IPAC__EXD)) {1172				istad = ReadISAC(isac, ISAC_ISTA);1173				pr_debug("%s: ISTAD %02x\n", ipac->name, istad);1174				if (istad & IPAC_D_TIN2)1175					pr_debug("%s TIN2 irq\n", ipac->name);1176				if (ista & IPAC__EXD)1177					istad |= 1; /* ISAC EXI */1178				mISDNisac_irq(isac, istad);1179			}1180			if (ista & (IPAC__ICA | IPAC__EXA))1181				ipac_irq(&ipac->hscx[0], ista);1182			if (ista & (IPAC__ICB | IPAC__EXB))1183				ipac_irq(&ipac->hscx[1], ista);1184			ista = ReadIPAC(ipac, IPAC_ISTA);1185		}1186	} else if (ipac->type & IPAC_TYPE_HSCX) {1187		while (--cnt) {1188			ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);1189			pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);1190			if (ista)1191				ipac_irq(&ipac->hscx[1], ista);1192			istad = ReadISAC(isac, ISAC_ISTA);1193			pr_debug("%s: ISTAD %02x\n", ipac->name, istad);1194			if (istad)1195				mISDNisac_irq(isac, istad);1196			if (0 == (ista | istad))1197				break;1198		}1199	}1200	if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */1201		return IRQ_NONE;1202	if (cnt < maxloop)1203		pr_debug("%s: %d irqloops cpu%d\n", ipac->name,1204			 maxloop - cnt, smp_processor_id());1205	if (maxloop && !cnt)1206		pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,1207			  maxloop, smp_processor_id());1208	return IRQ_HANDLED;1209}1210EXPORT_SYMBOL(mISDNipac_irq);1211 1212static int1213hscx_mode(struct hscx_hw *hscx, u32 bprotocol)1214{1215	pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,1216		 '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);1217	if (hscx->ip->type & IPAC_TYPE_IPACX) {1218		if (hscx->bch.nr & 1) { /* B1 and ICA */1219			WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);1220			WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);1221		} else { /* B2 and ICB */1222			WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);1223			WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);1224		}1225		switch (bprotocol) {1226		case ISDN_P_NONE: /* init */1227			WriteHSCX(hscx, IPACX_MODEB, 0xC0);	/* rec off */1228			WriteHSCX(hscx, IPACX_EXMB,  0x30);	/* std adj. */1229			WriteHSCX(hscx, IPACX_MASKB, 0xFF);	/* ints off */1230			hscx_cmdr(hscx, 0x41);1231			test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1232			test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1233			break;1234		case ISDN_P_B_RAW:1235			WriteHSCX(hscx, IPACX_MODEB, 0x88);	/* ex trans */1236			WriteHSCX(hscx, IPACX_EXMB,  0x00);	/* trans */1237			hscx_cmdr(hscx, 0x41);1238			WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);1239			test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1240			break;1241		case ISDN_P_B_HDLC:1242			WriteHSCX(hscx, IPACX_MODEB, 0xC0);	/* trans */1243			WriteHSCX(hscx, IPACX_EXMB,  0x00);	/* hdlc,crc */1244			hscx_cmdr(hscx, 0x41);1245			WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);1246			test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1247			break;1248		default:1249			pr_info("%s: protocol not known %x\n", hscx->ip->name,1250				bprotocol);1251			return -ENOPROTOOPT;1252		}1253	} else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */1254		WriteHSCX(hscx, IPAC_CCR1, 0x82);1255		WriteHSCX(hscx, IPAC_CCR2, 0x30);1256		WriteHSCX(hscx, IPAC_XCCR, 0x07);1257		WriteHSCX(hscx, IPAC_RCCR, 0x07);1258		WriteHSCX(hscx, IPAC_TSAX, hscx->slot);1259		WriteHSCX(hscx, IPAC_TSAR, hscx->slot);1260		switch (bprotocol) {1261		case ISDN_P_NONE:1262			WriteHSCX(hscx, IPAC_TSAX, 0x1F);1263			WriteHSCX(hscx, IPAC_TSAR, 0x1F);1264			WriteHSCX(hscx, IPAC_MODEB, 0x84);1265			WriteHSCX(hscx, IPAC_CCR1, 0x82);1266			WriteHSCX(hscx, IPAC_MASKB, 0xFF);	/* ints off */1267			test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1268			test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1269			break;1270		case ISDN_P_B_RAW:1271			WriteHSCX(hscx, IPAC_MODEB, 0xe4);	/* ex trans */1272			WriteHSCX(hscx, IPAC_CCR1, 0x82);1273			hscx_cmdr(hscx, 0x41);1274			WriteHSCX(hscx, IPAC_MASKB, 0);1275			test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1276			break;1277		case ISDN_P_B_HDLC:1278			WriteHSCX(hscx, IPAC_MODEB, 0x8c);1279			WriteHSCX(hscx, IPAC_CCR1, 0x8a);1280			hscx_cmdr(hscx, 0x41);1281			WriteHSCX(hscx, IPAC_MASKB, 0);1282			test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1283			break;1284		default:1285			pr_info("%s: protocol not known %x\n", hscx->ip->name,1286				bprotocol);1287			return -ENOPROTOOPT;1288		}1289	} else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */1290		WriteHSCX(hscx, IPAC_CCR1, 0x85);1291		WriteHSCX(hscx, IPAC_CCR2, 0x30);1292		WriteHSCX(hscx, IPAC_XCCR, 0x07);1293		WriteHSCX(hscx, IPAC_RCCR, 0x07);1294		WriteHSCX(hscx, IPAC_TSAX, hscx->slot);1295		WriteHSCX(hscx, IPAC_TSAR, hscx->slot);1296		switch (bprotocol) {1297		case ISDN_P_NONE:1298			WriteHSCX(hscx, IPAC_TSAX, 0x1F);1299			WriteHSCX(hscx, IPAC_TSAR, 0x1F);1300			WriteHSCX(hscx, IPAC_MODEB, 0x84);1301			WriteHSCX(hscx, IPAC_CCR1, 0x85);1302			WriteHSCX(hscx, IPAC_MASKB, 0xFF);	/* ints off */1303			test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1304			test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1305			break;1306		case ISDN_P_B_RAW:1307			WriteHSCX(hscx, IPAC_MODEB, 0xe4);	/* ex trans */1308			WriteHSCX(hscx, IPAC_CCR1, 0x85);1309			hscx_cmdr(hscx, 0x41);1310			WriteHSCX(hscx, IPAC_MASKB, 0);1311			test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1312			break;1313		case ISDN_P_B_HDLC:1314			WriteHSCX(hscx, IPAC_MODEB, 0x8c);1315			WriteHSCX(hscx, IPAC_CCR1, 0x8d);1316			hscx_cmdr(hscx, 0x41);1317			WriteHSCX(hscx, IPAC_MASKB, 0);1318			test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1319			break;1320		default:1321			pr_info("%s: protocol not known %x\n", hscx->ip->name,1322				bprotocol);1323			return -ENOPROTOOPT;1324		}1325	} else1326		return -EINVAL;1327	hscx->bch.state = bprotocol;1328	return 0;1329}1330 1331static int1332hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)1333{1334	struct bchannel *bch = container_of(ch, struct bchannel, ch);1335	struct hscx_hw	*hx = container_of(bch, struct hscx_hw, bch);1336	int ret = -EINVAL;1337	struct mISDNhead *hh = mISDN_HEAD_P(skb);1338	unsigned long flags;1339 1340	switch (hh->prim) {1341	case PH_DATA_REQ:1342		spin_lock_irqsave(hx->ip->hwlock, flags);1343		ret = bchannel_senddata(bch, skb);1344		if (ret > 0) { /* direct TX */1345			ret = 0;1346			hscx_fill_fifo(hx);1347		}1348		spin_unlock_irqrestore(hx->ip->hwlock, flags);1349		return ret;1350	case PH_ACTIVATE_REQ:1351		spin_lock_irqsave(hx->ip->hwlock, flags);1352		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))1353			ret = hscx_mode(hx, ch->protocol);1354		else1355			ret = 0;1356		spin_unlock_irqrestore(hx->ip->hwlock, flags);1357		if (!ret)1358			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,1359				    NULL, GFP_KERNEL);1360		break;1361	case PH_DEACTIVATE_REQ:1362		spin_lock_irqsave(hx->ip->hwlock, flags);1363		mISDN_clear_bchannel(bch);1364		hscx_mode(hx, ISDN_P_NONE);1365		spin_unlock_irqrestore(hx->ip->hwlock, flags);1366		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,1367			    NULL, GFP_KERNEL);1368		ret = 0;1369		break;1370	default:1371		pr_info("%s: %s unknown prim(%x,%x)\n",1372			hx->ip->name, __func__, hh->prim, hh->id);1373		ret = -EINVAL;1374	}1375	if (!ret)1376		dev_kfree_skb(skb);1377	return ret;1378}1379 1380static int1381channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)1382{1383	return mISDN_ctrl_bchannel(bch, cq);1384}1385 1386static int1387hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)1388{1389	struct bchannel *bch = container_of(ch, struct bchannel, ch);1390	struct hscx_hw	*hx = container_of(bch, struct hscx_hw, bch);1391	int ret = -EINVAL;1392	u_long flags;1393 1394	pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);1395	switch (cmd) {1396	case CLOSE_CHANNEL:1397		test_and_clear_bit(FLG_OPEN, &bch->Flags);1398		cancel_work_sync(&bch->workq);1399		spin_lock_irqsave(hx->ip->hwlock, flags);1400		mISDN_clear_bchannel(bch);1401		hscx_mode(hx, ISDN_P_NONE);1402		spin_unlock_irqrestore(hx->ip->hwlock, flags);1403		ch->protocol = ISDN_P_NONE;1404		ch->peer = NULL;1405		module_put(hx->ip->owner);1406		ret = 0;1407		break;1408	case CONTROL_CHANNEL:1409		ret = channel_bctrl(bch, arg);1410		break;1411	default:1412		pr_info("%s: %s unknown prim(%x)\n",1413			hx->ip->name, __func__, cmd);1414	}1415	return ret;1416}1417 1418static void1419free_ipac(struct ipac_hw *ipac)1420{1421	isac_release(&ipac->isac);1422}1423 1424static const char *HSCXVer[] =1425{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",1426 "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};1427 1428 1429 1430static void1431hscx_init(struct hscx_hw *hx)1432{1433	u8 val;1434 1435	WriteHSCX(hx, IPAC_RAH2, 0xFF);1436	WriteHSCX(hx, IPAC_XBCH, 0x00);1437	WriteHSCX(hx, IPAC_RLCR, 0x00);1438 1439	if (hx->ip->type & IPAC_TYPE_HSCX) {1440		WriteHSCX(hx, IPAC_CCR1, 0x85);1441		val = ReadHSCX(hx, HSCX_VSTR);1442		pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);1443		if (hx->bch.debug & DEBUG_HW)1444			pr_notice("%s: HSCX version %s\n", hx->ip->name,1445				  HSCXVer[val & 0x0f]);1446	} else1447		WriteHSCX(hx, IPAC_CCR1, 0x82);1448	WriteHSCX(hx, IPAC_CCR2, 0x30);1449	WriteHSCX(hx, IPAC_XCCR, 0x07);1450	WriteHSCX(hx, IPAC_RCCR, 0x07);1451}1452 1453static int1454ipac_init(struct ipac_hw *ipac)1455{1456	u8 val;1457 1458	if (ipac->type & IPAC_TYPE_HSCX) {1459		hscx_init(&ipac->hscx[0]);1460		hscx_init(&ipac->hscx[1]);1461		val = ReadIPAC(ipac, IPAC_ID);1462	} else if (ipac->type & IPAC_TYPE_IPAC) {1463		hscx_init(&ipac->hscx[0]);1464		hscx_init(&ipac->hscx[1]);1465		WriteIPAC(ipac, IPAC_MASK, IPAC__ON);1466		val = ReadIPAC(ipac, IPAC_CONF);1467		/* conf is default 0, but can be overwritten by card setup */1468		pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,1469			 val, ipac->conf);1470		WriteIPAC(ipac, IPAC_CONF, ipac->conf);1471		val = ReadIPAC(ipac, IPAC_ID);1472		if (ipac->hscx[0].bch.debug & DEBUG_HW)1473			pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);1474	}1475	/* nothing special for IPACX to do here */1476	return isac_init(&ipac->isac);1477}1478 1479static int1480open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)1481{1482	struct bchannel		*bch;1483 1484	if (rq->adr.channel == 0 || rq->adr.channel > 2)1485		return -EINVAL;1486	if (rq->protocol == ISDN_P_NONE)1487		return -EINVAL;1488	bch = &ipac->hscx[rq->adr.channel - 1].bch;1489	if (test_and_set_bit(FLG_OPEN, &bch->Flags))1490		return -EBUSY; /* b-channel can be only open once */1491	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);1492	bch->ch.protocol = rq->protocol;1493	rq->ch = &bch->ch;1494	return 0;1495}1496 1497static int1498channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)1499{1500	int	ret = 0;1501 1502	switch (cq->op) {1503	case MISDN_CTRL_GETOP:1504		cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;1505		break;1506	case MISDN_CTRL_LOOP:1507		/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */1508		if (cq->channel < 0 || cq->channel > 3) {1509			ret = -EINVAL;1510			break;1511		}1512		ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);1513		break;1514	case MISDN_CTRL_L1_TIMER3:1515		ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1);1516		break;1517	default:1518		pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);1519		ret = -EINVAL;1520		break;1521	}1522	return ret;1523}1524 1525static int1526ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)1527{1528	struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);1529	struct dchannel *dch = container_of(dev, struct dchannel, dev);1530	struct isac_hw *isac = container_of(dch, struct isac_hw, dch);1531	struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);1532	struct channel_req *rq;1533	int err = 0;1534 1535	pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);1536	switch (cmd) {1537	case OPEN_CHANNEL:1538		rq = arg;1539		if (rq->protocol == ISDN_P_TE_S0)1540			err = open_dchannel_caller(isac, rq, __builtin_return_address(0));1541		else1542			err = open_bchannel(ipac, rq);1543		if (err)1544			break;1545		if (!try_module_get(ipac->owner))1546			pr_info("%s: cannot get module\n", ipac->name);1547		break;1548	case CLOSE_CHANNEL:1549		pr_debug("%s: dev(%d) close from %p\n", ipac->name,1550			 dch->dev.id, __builtin_return_address(0));1551		module_put(ipac->owner);1552		break;1553	case CONTROL_CHANNEL:1554		err = channel_ctrl(ipac, arg);1555		break;1556	default:1557		pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);1558		return -EINVAL;1559	}1560	return err;1561}1562 1563u321564mISDNipac_init(struct ipac_hw *ipac, void *hw)1565{1566	u32 ret;1567	u8 i;1568 1569	ipac->hw = hw;1570	if (ipac->isac.dch.debug & DEBUG_HW)1571		pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);1572	if (ipac->type & IPAC_TYPE_HSCX) {1573		ipac->isac.type = IPAC_TYPE_ISAC;1574		ipac->hscx[0].off = 0;1575		ipac->hscx[1].off = 0x40;1576		ipac->hscx[0].fifo_size = 32;1577		ipac->hscx[1].fifo_size = 32;1578	} else if (ipac->type & IPAC_TYPE_IPAC) {1579		ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;1580		ipac->hscx[0].off = 0;1581		ipac->hscx[1].off = 0x40;1582		ipac->hscx[0].fifo_size = 64;1583		ipac->hscx[1].fifo_size = 64;1584	} else if (ipac->type & IPAC_TYPE_IPACX) {1585		ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;1586		ipac->hscx[0].off = IPACX_OFF_ICA;1587		ipac->hscx[1].off = IPACX_OFF_ICB;1588		ipac->hscx[0].fifo_size = 64;1589		ipac->hscx[1].fifo_size = 64;1590	} else1591		return 0;1592 1593	mISDNisac_init(&ipac->isac, hw);1594 1595	ipac->isac.dch.dev.D.ctrl = ipac_dctrl;1596 1597	for (i = 0; i < 2; i++) {1598		ipac->hscx[i].bch.nr = i + 1;1599		set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);1600		list_add(&ipac->hscx[i].bch.ch.list,1601			 &ipac->isac.dch.dev.bchannels);1602		mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM,1603				   ipac->hscx[i].fifo_size);1604		ipac->hscx[i].bch.ch.nr = i + 1;1605		ipac->hscx[i].bch.ch.send = &hscx_l2l1;1606		ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;1607		ipac->hscx[i].bch.hw = hw;1608		ipac->hscx[i].ip = ipac;1609		/* default values for IOM time slots1610		 * can be overwritten by card */1611		ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;1612	}1613 1614	ipac->init = ipac_init;1615	ipac->release = free_ipac;1616 1617	ret =	(1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |1618		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));1619	return ret;1620}1621EXPORT_SYMBOL(mISDNipac_init);1622 1623static int __init1624isac_mod_init(void)1625{1626	pr_notice("mISDNipac module version %s\n", ISAC_REV);1627	return 0;1628}1629 1630static void __exit1631isac_mod_cleanup(void)1632{1633	pr_notice("mISDNipac module unloaded\n");1634}1635module_init(isac_mod_init);1636module_exit(isac_mod_cleanup);1637