The negation makes it a bool before the comparison and hence it will never be 0x40. Signed-off-by: Roel Kluin <roel.kluin@gmail.com> Cc: Karsten Keil <isdn@linux-pingi.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			292 lines
		
	
	
	
		
			7.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
	
		
			7.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
 | 
						|
 *
 | 
						|
 * low level b-channel stuff for Siemens HSCX
 | 
						|
 *
 | 
						|
 * Author       Karsten Keil
 | 
						|
 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
 | 
						|
 * 
 | 
						|
 * This software may be used and distributed according to the terms
 | 
						|
 * of the GNU General Public License, incorporated herein by reference.
 | 
						|
 *
 | 
						|
 * This is an include file for fast inline IRQ stuff
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
static inline void
 | 
						|
waitforCEC(struct IsdnCardState *cs, int hscx)
 | 
						|
{
 | 
						|
	int to = 50;
 | 
						|
 | 
						|
	while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
 | 
						|
		udelay(1);
 | 
						|
		to--;
 | 
						|
	}
 | 
						|
	if (!to)
 | 
						|
		printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static inline void
 | 
						|
waitforXFW(struct IsdnCardState *cs, int hscx)
 | 
						|
{
 | 
						|
	int to = 50;
 | 
						|
 | 
						|
	while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
 | 
						|
		udelay(1);
 | 
						|
		to--;
 | 
						|
	}
 | 
						|
	if (!to)
 | 
						|
		printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
 | 
						|
{
 | 
						|
	waitforCEC(cs, hscx);
 | 
						|
	WRITEHSCX(cs, hscx, HSCX_CMDR, data);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
hscx_empty_fifo(struct BCState *bcs, int count)
 | 
						|
{
 | 
						|
	u_char *ptr;
 | 
						|
	struct IsdnCardState *cs = bcs->cs;
 | 
						|
 | 
						|
	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 | 
						|
		debugl1(cs, "hscx_empty_fifo");
 | 
						|
 | 
						|
	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
 | 
						|
		if (cs->debug & L1_DEB_WARN)
 | 
						|
			debugl1(cs, "hscx_empty_fifo: incoming packet too large");
 | 
						|
		WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
 | 
						|
		bcs->hw.hscx.rcvidx = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
 | 
						|
	bcs->hw.hscx.rcvidx += count;
 | 
						|
	READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
 | 
						|
	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
 | 
						|
	if (cs->debug & L1_DEB_HSCX_FIFO) {
 | 
						|
		char *t = bcs->blog;
 | 
						|
 | 
						|
		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
 | 
						|
			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
 | 
						|
		QuickHex(t, ptr, count);
 | 
						|
		debugl1(cs, bcs->blog);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
hscx_fill_fifo(struct BCState *bcs)
 | 
						|
{
 | 
						|
	struct IsdnCardState *cs = bcs->cs;
 | 
						|
	int more, count;
 | 
						|
	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
 | 
						|
	u_char *ptr;
 | 
						|
 | 
						|
	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 | 
						|
		debugl1(cs, "hscx_fill_fifo");
 | 
						|
 | 
						|
	if (!bcs->tx_skb)
 | 
						|
		return;
 | 
						|
	if (bcs->tx_skb->len <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
 | 
						|
	if (bcs->tx_skb->len > fifo_size) {
 | 
						|
		more = !0;
 | 
						|
		count = fifo_size;
 | 
						|
	} else
 | 
						|
		count = bcs->tx_skb->len;
 | 
						|
 | 
						|
	waitforXFW(cs, bcs->hw.hscx.hscx);
 | 
						|
	ptr = bcs->tx_skb->data;
 | 
						|
	skb_pull(bcs->tx_skb, count);
 | 
						|
	bcs->tx_cnt -= count;
 | 
						|
	bcs->hw.hscx.count += count;
 | 
						|
	WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
 | 
						|
	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
 | 
						|
	if (cs->debug & L1_DEB_HSCX_FIFO) {
 | 
						|
		char *t = bcs->blog;
 | 
						|
 | 
						|
		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
 | 
						|
			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
 | 
						|
		QuickHex(t, ptr, count);
 | 
						|
		debugl1(cs, bcs->blog);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 | 
						|
{
 | 
						|
	u_char r;
 | 
						|
	struct BCState *bcs = cs->bcs + hscx;
 | 
						|
	struct sk_buff *skb;
 | 
						|
	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
 | 
						|
	int count;
 | 
						|
 | 
						|
	if (!test_bit(BC_FLG_INIT, &bcs->Flag))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (val & 0x80) {	/* RME */
 | 
						|
		r = READHSCX(cs, hscx, HSCX_RSTA);
 | 
						|
		if ((r & 0xf0) != 0xa0) {
 | 
						|
			if (!(r & 0x80)) {
 | 
						|
				if (cs->debug & L1_DEB_WARN)
 | 
						|
					debugl1(cs, "HSCX invalid frame");
 | 
						|
#ifdef ERROR_STATISTIC
 | 
						|
				bcs->err_inv++;
 | 
						|
#endif
 | 
						|
			}
 | 
						|
			if ((r & 0x40) && bcs->mode) {
 | 
						|
				if (cs->debug & L1_DEB_WARN)
 | 
						|
					debugl1(cs, "HSCX RDO mode=%d",
 | 
						|
						bcs->mode);
 | 
						|
#ifdef ERROR_STATISTIC
 | 
						|
				bcs->err_rdo++;
 | 
						|
#endif
 | 
						|
			}
 | 
						|
			if (!(r & 0x20)) {
 | 
						|
				if (cs->debug & L1_DEB_WARN)
 | 
						|
					debugl1(cs, "HSCX CRC error");
 | 
						|
#ifdef ERROR_STATISTIC
 | 
						|
				bcs->err_crc++;
 | 
						|
#endif
 | 
						|
			}
 | 
						|
			WriteHSCXCMDR(cs, hscx, 0x80);
 | 
						|
		} else {
 | 
						|
			count = READHSCX(cs, hscx, HSCX_RBCL) & (
 | 
						|
				test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
 | 
						|
			if (count == 0)
 | 
						|
				count = fifo_size;
 | 
						|
			hscx_empty_fifo(bcs, count);
 | 
						|
			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
 | 
						|
				if (cs->debug & L1_DEB_HSCX_FIFO)
 | 
						|
					debugl1(cs, "HX Frame %d", count);
 | 
						|
				if (!(skb = dev_alloc_skb(count)))
 | 
						|
					printk(KERN_WARNING "HSCX: receive out of memory\n");
 | 
						|
				else {
 | 
						|
					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
 | 
						|
					skb_queue_tail(&bcs->rqueue, skb);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		bcs->hw.hscx.rcvidx = 0;
 | 
						|
		schedule_event(bcs, B_RCVBUFREADY);
 | 
						|
	}
 | 
						|
	if (val & 0x40) {	/* RPF */
 | 
						|
		hscx_empty_fifo(bcs, fifo_size);
 | 
						|
		if (bcs->mode == L1_MODE_TRANS) {
 | 
						|
			/* receive audio data */
 | 
						|
			if (!(skb = dev_alloc_skb(fifo_size)))
 | 
						|
				printk(KERN_WARNING "HiSax: receive out of memory\n");
 | 
						|
			else {
 | 
						|
				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
 | 
						|
				skb_queue_tail(&bcs->rqueue, skb);
 | 
						|
			}
 | 
						|
			bcs->hw.hscx.rcvidx = 0;
 | 
						|
			schedule_event(bcs, B_RCVBUFREADY);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (val & 0x10) {	/* XPR */
 | 
						|
		if (bcs->tx_skb) {
 | 
						|
			if (bcs->tx_skb->len) {
 | 
						|
				hscx_fill_fifo(bcs);
 | 
						|
				return;
 | 
						|
			} else {
 | 
						|
				if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
 | 
						|
					(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
 | 
						|
					u_long	flags;
 | 
						|
					spin_lock_irqsave(&bcs->aclock, flags);
 | 
						|
					bcs->ackcnt += bcs->hw.hscx.count;
 | 
						|
					spin_unlock_irqrestore(&bcs->aclock, flags);
 | 
						|
					schedule_event(bcs, B_ACKPENDING);
 | 
						|
				}
 | 
						|
				dev_kfree_skb_irq(bcs->tx_skb);
 | 
						|
				bcs->hw.hscx.count = 0; 
 | 
						|
				bcs->tx_skb = NULL;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
 | 
						|
			bcs->hw.hscx.count = 0;
 | 
						|
			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
 | 
						|
			hscx_fill_fifo(bcs);
 | 
						|
		} else {
 | 
						|
			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 | 
						|
			schedule_event(bcs, B_XMTBUFREADY);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
hscx_int_main(struct IsdnCardState *cs, u_char val)
 | 
						|
{
 | 
						|
 | 
						|
	u_char exval;
 | 
						|
	struct BCState *bcs;
 | 
						|
 | 
						|
	if (val & 0x01) {
 | 
						|
		bcs = cs->bcs + 1;
 | 
						|
		exval = READHSCX(cs, 1, HSCX_EXIR);
 | 
						|
		if (exval & 0x40) {
 | 
						|
			if (bcs->mode == 1)
 | 
						|
				hscx_fill_fifo(bcs);
 | 
						|
			else {
 | 
						|
#ifdef ERROR_STATISTIC
 | 
						|
				bcs->err_tx++;
 | 
						|
#endif
 | 
						|
				/* Here we lost an TX interrupt, so
 | 
						|
				   * restart transmitting the whole frame.
 | 
						|
				 */
 | 
						|
				if (bcs->tx_skb) {
 | 
						|
					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 | 
						|
					bcs->tx_cnt += bcs->hw.hscx.count;
 | 
						|
					bcs->hw.hscx.count = 0;
 | 
						|
				}
 | 
						|
				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
 | 
						|
				if (cs->debug & L1_DEB_WARN)
 | 
						|
					debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
 | 
						|
			}
 | 
						|
		} else if (cs->debug & L1_DEB_HSCX)
 | 
						|
			debugl1(cs, "HSCX B EXIR %x", exval);
 | 
						|
	}
 | 
						|
	if (val & 0xf8) {
 | 
						|
		if (cs->debug & L1_DEB_HSCX)
 | 
						|
			debugl1(cs, "HSCX B interrupt %x", val);
 | 
						|
		hscx_interrupt(cs, val, 1);
 | 
						|
	}
 | 
						|
	if (val & 0x02) {
 | 
						|
		bcs = cs->bcs;
 | 
						|
		exval = READHSCX(cs, 0, HSCX_EXIR);
 | 
						|
		if (exval & 0x40) {
 | 
						|
			if (bcs->mode == L1_MODE_TRANS)
 | 
						|
				hscx_fill_fifo(bcs);
 | 
						|
			else {
 | 
						|
				/* Here we lost an TX interrupt, so
 | 
						|
				   * restart transmitting the whole frame.
 | 
						|
				 */
 | 
						|
#ifdef ERROR_STATISTIC
 | 
						|
				bcs->err_tx++;
 | 
						|
#endif
 | 
						|
				if (bcs->tx_skb) {
 | 
						|
					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 | 
						|
					bcs->tx_cnt += bcs->hw.hscx.count;
 | 
						|
					bcs->hw.hscx.count = 0;
 | 
						|
				}
 | 
						|
				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
 | 
						|
				if (cs->debug & L1_DEB_WARN)
 | 
						|
					debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
 | 
						|
			}
 | 
						|
		} else if (cs->debug & L1_DEB_HSCX)
 | 
						|
			debugl1(cs, "HSCX A EXIR %x", exval);
 | 
						|
	}
 | 
						|
	if (val & 0x04) {
 | 
						|
		exval = READHSCX(cs, 0, HSCX_ISTA);
 | 
						|
		if (cs->debug & L1_DEB_HSCX)
 | 
						|
			debugl1(cs, "HSCX A interrupt %x", exval);
 | 
						|
		hscx_interrupt(cs, exval, 0);
 | 
						|
	}
 | 
						|
}
 |