📄 hfc_sx.c
字号:
/* $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_BOARDstatic 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 voidWrite_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_charRead_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 voidfifo_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 voidreset_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 intwrite_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 */ 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)); if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)", fifo, f1, f2, z1, z2); /* now determine bytes in actual FIFO buffer */ count = z1 - z2; if (count <= 0) count += fifo_size; /* count now contains buffered bytes */ count++; if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d count %ld)", fifo, count); if ((count > fifo_size) || (count < 4)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count); while (count) { count--; /* empty fifo */ Read_hfc(cs, HFCSX_FIF_DRD); } skb = NULL; } else if ((skb = dev_alloc_skb(count - 3))) { count -= 3; dst = skb_put(skb, count); while (count--) *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ if (Read_hfc(cs, HFCSX_FIF_DRD)) { dev_kfree_skb_irq(skb); if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); skb = NULL; } } else { printk(KERN_WARNING "HFC-SX: receive out of memory\n"); return(NULL); } Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */ udelay(1); while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ udelay(1); } while (!skb); /* retry in case of crc error */ return(skb);} /******************************************//* free hardware resources used by driver *//******************************************/static voidrelease_io_hfcsx(struct IsdnCardState *cs){ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ msleep(30); /* Timeout 30ms */ Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ del_timer(&cs->hw.hfcsx.timer); release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ kfree(cs->hw.hfcsx.extra); cs->hw.hfcsx.extra = NULL;}/**********************************************************//* set_fifo_size determines the size of the RAM and FIFOs *//* returning 0 -> need to reset the chip again. *//**********************************************************/static int set_fifo_size(struct IsdnCardState *cs){ if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */ if ((cs->hw.hfcsx.chip >> 4) == 9) { cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K; return(1); } cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K; cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */ return(0);}/********************************************************************************//* function called to reset the HFC SX chip. A complete software reset of chip *//* and fifos is done. *//********************************************************************************/static voidreset_hfcsx(struct IsdnCardState *cs){ cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); printk(KERN_INFO "HFC_SX: resetting card\n"); while (1) { Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */ mdelay(30); Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ mdelay(20); if (Read_hfc(cs, HFCSX_STATUS) & 2) printk(KERN_WARNING "HFC-SX init bit busy\n"); cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ if (!set_fifo_size(cs)) continue; break; } cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE; Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */ cs->hw.hfcsx.bswapped = 0; /* no exchange */ cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */ cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER; Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER; Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); /* Clear already pending ints */ if (Read_hfc(cs, HFCSX_INT_S1)); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */ udelay(10); Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */ cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */ Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); cs->hw.hfcsx.sctrl_r = 0; Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); /* Init GCI/IOM2 in master mode */ /* Slots 0 and 1 are set for B-chan 1 and 2 */ /* D- and monitor/CI channel are not enabled */ /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ /* STIO2 is used as data input, B1+B2 from IOM->ST */ /* ST B-channel send disabled -> continous 1s */ /* The IOM slots are always enabled */ cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ /* Finally enable IRQ output */ cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); if (Read_hfc(cs, HFCSX_INT_S2));}/***************************************************//* Timer function called when kernel timer expires *//***************************************************/static voidhfcsx_Timer(struct IsdnCardState *cs){ cs->hw.hfcsx.timer.expires = jiffies + 75; /* WD RESET *//* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80); add_timer(&cs->hw.hfcsx.timer); */}/************************************************//* select a b-channel entry matching and active *//************************************************/staticstruct BCState *Sel_BCS(struct IsdnCardState *cs, int channel){ if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) return (&cs->bcs[0]); else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) return (&cs->bcs[1]); else return (NULL);}/*******************************//* D-channel receive procedure *//*******************************/staticintreceive_dmsg(struct IsdnCardState *cs){ struct sk_buff *skb; int count = 5; if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { debugl1(cs, "rec_dmsg blocked"); return (1); } do { skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); if (skb) { skb_queue_tail(&cs->rq, skb); schedule_event(cs, D_RCVBUFREADY); } } while (--count && skb); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); return (1);}/**********************************//* B-channel main receive routine *//**********************************/static voidmain_rec_hfcsx(struct BCState *bcs){ struct IsdnCardState *cs = bcs->cs; int count = 5; struct sk_buff *skb; Begin: count--; if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { debugl1(cs, "rec_data %d blocked", bcs->channel); return; } skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, (bcs->mode == L1_MODE_TRANS) ? HFCSX_BTRANS_THRESHOLD : 0); if (skb) { skb_queue_tail(&bcs->rqueue, skb); schedule_event(bcs, B_RCVBUFREADY); } test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && skb) goto Begin; return;}/**************************//* D-channel send routine *//**************************/static voidhfcsx_fill_dfifo(struct IsdnCardState *cs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -