/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $
*
* level driver for Cologne Chip Designs hfc-s+/sp based cards
*
* Author Werner Cornelius
* based on existing driver for CCD HFC PCI cards
* Copyright by Werner Cornelius <werner@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hfc_sx.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/isapnp.h>
extern const char *CardType[];
static const char *hfcsx_revision = "$Revision: 1.12.2.5 $";
/***************************************/
/* IRQ-table for CCDs demo board */
/* IRQs 6,5,10,11,12,15 are supported */
/***************************************/
/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1
*
* Thanks to Uwe Wisniewski
*
* ISA-SLOT Signal PIN
* B25 IRQ3 92 IRQ_G
* B23 IRQ5 94 IRQ_A
* B4 IRQ2/9 95 IRQ_B
* D3 IRQ10 96 IRQ_C
* D4 IRQ11 97 IRQ_D
* D5 IRQ12 98 IRQ_E
* D6 IRQ15 99 IRQ_F
*/
#undef CCD_DEMO_BOARD
#ifdef CCD_DEMO_BOARD
static u_char ccd_sp_irqtab[16] = {
0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6
};
#else /* Teles 16.3c */
static u_char ccd_sp_irqtab[16] = {
0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6
};
#endif
#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
/******************************/
/* In/Out access to registers */
/******************************/
static inline void
Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val)
{
byteout(cs->hw.hfcsx.base+1, regnum);
byteout(cs->hw.hfcsx.base, val);
}
static inline u_char
Read_hfc(struct IsdnCardState *cs, u_char regnum)
{
u_char ret;
byteout(cs->hw.hfcsx.base+1, regnum);
ret = bytein(cs->hw.hfcsx.base);
return(ret);
}
/**************************************************/
/* select a fifo and remember which one for reuse */
/**************************************************/
static void
fifo_select(struct IsdnCardState *cs, u_char fifo)
{
if (fifo == cs->hw.hfcsx.last_fifo)
return; /* still valid */
byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL);
byteout(cs->hw.hfcsx.base, fifo);
while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
udelay(4);
byteout(cs->hw.hfcsx.base, fifo);
while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
}
/******************************************/
/* reset the specified fifo to defaults. */
/* If its a send fifo init needed markers */
/******************************************/
static void
reset_fifo(struct IsdnCardState *cs, u_char fifo)
{
fifo_select(cs, fifo); /* first select the fifo */
byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM);
byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */
udelay(1);
while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
}
/*************************************************************/
/* write_fifo writes the skb contents to the desired fifo */
/* if no space is available or an error occurs 0 is returned */
/* the skb is not released in any way. */
/*************************************************************/
static int
write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max)
{
unsigned short *msp;
int fifo_size, count, z1, z2;
u_char f_msk, f1, f2, *src;
if (skb->len <= 0) return(0);
if (fifo & 1) return(0); /* no write fifo */
fifo_select(cs, fifo);
if (fifo & 4) {
fifo_size = D_FIFO_SIZE; /* D-channel */
f_msk = MAX_D_FRAMES;
if (trans_max) return(0); /* only HDLC */
}
else {
fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
f_msk = MAX_B_FRAMES;
}
z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
/* Check for transparent mode */
if (trans_max) {
z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
count = z2 - z1;
if (count <= 0)
count += fifo_size; /* free bytes */
if (count < skb->len+1) return(0); /* no room */
count = fifo_size - count; /* bytes still not send */
if (count > 2 * trans_max) return(0); /* delay to long */
count = skb->len;
src = skb->data;
while (count--)
Write_hfc(cs, HFCSX_FIF_DWR, *src++);
return(1); /* success */
}
msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker;
msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1));
f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
count = f1 - f2; /* frame count actually buffered */
if (count < 0)
count += (f_msk + 1); /* if wrap around */
if (count > f_msk-1) {
if (cs->debug & L1_DEB_ISAC_FIFO)
debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1);
return(0);
}
*(msp + f1) = z1; /* remember marker */
if (cs->debug & L1_DEB_ISAC_FIFO)
debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)",
fifo, f1, f2, z1);
/* now determine free bytes in FIFO buffer */
count = *(msp + f2) - z1;
if (count <= 0)
count += fifo_size; /* count now contains available bytes */
if (cs->debug & L1_DEB_ISAC_FIFO)
debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
fifo, skb->len, count);
if (count < skb->len) {
if (cs->debug & L1_DEB_ISAC_FIFO)
debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo);
return(0);
}
count = skb->len; /* get frame len */
src = skb->data; /* source pointer */
while (count--)
Write_hfc(cs, HFCSX_FIF_DWR, *src++);
Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */
udelay(1);
while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */
return(1);
}
/***************************************************************/
/* read_fifo reads data to an skb from the desired fifo */
/* if no data is available or an error occurs NULL is returned */
/* the skb is not released in any way. */
/***************************************************************/
static struct sk_buff *
read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
{ int fifo_size, count, z1, z2;
u_char f_msk, f1, f2, *dst;
struct sk_buff *skb;
if (!(fifo & 1)) return(NULL); /* no read fifo */
fifo_select(cs, fifo);
if (fifo & 4) {
fifo_size = D_FIFO_SIZE; /* D-channel */
f_msk = MAX_D_FRAMES;
if (trans_max) return(NULL); /* only hdlc */
}
else {
fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */
f_msk = MAX_B_FRAMES;
}
/* transparent mode */
if (trans_max) {
z1 = Read_hfc(cs, HFCSX_FIF_Z1H);
z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L));
z2 = Read_hfc(cs, HFCSX_FIF_Z2H);
z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L));
/* now determine bytes in actual FIFO buffer */
count = z1 - z2;
if (count <= 0)
count += fifo_size; /* count now contains buffered bytes */
count++;
if (count > trans_max)
count = trans_max; /* limit length */
if ((skb = dev_alloc_skb(count))) {
dst = skb_put(skb, count);
while (count--)
*dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
return(skb);
}
else return(NULL); /* no memory */
}
do {
f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk;
f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk;
if (f1 == f2) return(NULL); /* no frame available */
|