From cb620d8ecc82128738d8f2781dd57d4c9873c80e Mon Sep 17 00:00:00 2001 From: Noe Rubinstein Date: Fri, 17 Dec 2010 14:42:39 +0100 Subject: move xhfc.c to base.c and rename module to xivoxhfc.c --- xhfc/Makefile | 4 +- xhfc/base.c | 1202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xhfc/xhfc.c | 1202 --------------------------------------------------------- 3 files changed, 1204 insertions(+), 1204 deletions(-) create mode 100644 xhfc/base.c delete mode 100644 xhfc/xhfc.c diff --git a/xhfc/Makefile b/xhfc/Makefile index a7c8833..a1f7f05 100644 --- a/xhfc/Makefile +++ b/xhfc/Makefile @@ -5,8 +5,8 @@ DAHDI_INCLUDE ?= /bad__dahdi_include__not_set CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(abspath $(src)/../) -DUSE_GPIO -obj-m := xhfcdm.o -xhfcdm-objs := xhfc.o xhfc_leb.o xhfc_st_state.o +obj-m := xivoxhfc.o +xhfcdm-objs := base.o xhfc_leb.o xhfc_st_state.o modules: modules modules_install clean: diff --git a/xhfc/base.c b/xhfc/base.c new file mode 100644 index 0000000..c2c9a02 --- /dev/null +++ b/xhfc/base.c @@ -0,0 +1,1202 @@ +#include +#include +#include +#include +#include + +#ifdef USE_GPIO +#include +#endif + +#include "xhfc24sucd.h" +#include "xhfc.h" +#include "xhfc_leb.h" + +static const char xhfc_rev[] = "$Revision: 1.22 $"; +static int card_cnt = 0; + +MODULE_LICENSE("GPL"); + +uint debug = 0; +uint dbg_spanfilter = 0xFFFFFFFF; +int exit_after_reset = 0; + +uint ntte = 0x3; + +#ifdef USE_GPIO +static uint reset_gpio = 21; +#endif + +int softconf = 0; + +module_param(debug, uint, S_IRUGO | S_IWUSR); +module_param(dbg_spanfilter, uint, S_IRUGO | S_IWUSR); +module_param(softconf, bool, S_IRUGO); +module_param(ntte, uint, S_IRUGO); +module_param(exit_after_reset, bool, S_IRUGO); +#ifdef USE_GPIO +module_param(reset_gpio, uint, S_IRUGO); +#endif + +MODULE_PARM_DESC(debug, "Debug bitfield:\n" + "\t0: general\n" + //"\t2: verbose register access, only if DEBUG is defined\n" + "\t3: file operations\n" + "\t4: (not used, echo canceller)\n" + "\t5: ST state\n" + "\t6: HDLC\n" + "\t7: HDLC (verbose)\n" + "\t8: timing\n" + "\t9: alarms\n"); +MODULE_PARM_DESC(dbg_spanfilter, "bitfield, filter debug info by span."); +MODULE_PARM_DESC(ntte, "bitfield, configuration of the physical ports. ex: 0x3 = 0 NT, 1 NT, 2 TE, 3 TE."); +MODULE_PARM_DESC(softconf, "Configure the S/T port line interface in software."); +#ifdef USE_GPIO +MODULE_PARM_DESC(reset_gpio, "Reset the XHFC using this GPIO"); +#endif +MODULE_PARM_DESC(exit_after_reset, "Exit after hard reset"); + +#ifdef AUDIO +#define RX_HISTO_NB 16 +static int rx_histo[RX_HISTO_NB]; +#endif + +void xhfc_waitbusy(struct xhfc *xhfc) +{ + while (read_xhfc(xhfc, R_STATUS) & M_BUSY) + cpu_relax(); +} + +void xhfc_selfifo(struct xhfc *xhfc, int fifo, int receive) +{ + u8 r_fifo = 0x00; + SET_V_FIFO_NUM(r_fifo, fifo); + SET_V_FIFO_DIR(r_fifo, receive); + write_xhfc(xhfc, R_FIFO, r_fifo); + xhfc_waitbusy(xhfc); +} + +void xhfc_inc_f(struct xhfc *xhfc) +{ + write_xhfc(xhfc, A_INC_RES_FIFO, M_INC_F); + xhfc_waitbusy(xhfc); +} + +static inline void xhfc_resetfifo(struct xhfc *xhfc) +{ + write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO | M_RES_FIFO_ERR); + xhfc_waitbusy(xhfc); +} + +int xhfc_reset(struct xhfc *xhfc) +{ + int timeout = 0x2000; + + /* software reset to enable R_FIFO_MD setting */ + write_xhfc(xhfc, R_CIRM, M_SRES); + udelay(5); + write_xhfc(xhfc, R_CIRM, 0); + + while ((read_xhfc(xhfc, R_STATUS) & (M_BUSY | M_PCM_INIT)) + && (timeout)) { + timeout--; + cpu_relax(); + } + + if (!(timeout)) { + printk(KERN_ERR + "%s %s: initialization sequence could not finish\n", + xhfc->pi->name, __func__); + return -EIO; + } + + return 0; +} + +void xhfc_config_st(struct xhfc *x, int port, int nt) +{ + u8 r_su_sel, a_su_ctrl0, a_su_ctrl1, a_su_ctrl2, a_su_wr_sta, a_su_clk_dly; + r_su_sel = a_su_ctrl0 = a_su_ctrl1 = a_su_ctrl2 = a_su_wr_sta = a_su_clk_dly = 0x00; + SET_V_SU_SEL(r_su_sel, port); + SET_V_SU_MD(a_su_ctrl0, !!nt); + SET_V_B1_TX_EN(a_su_ctrl0, 1); + SET_V_B2_TX_EN(a_su_ctrl0, 1); + SET_V_ST_E_IGNO(a_su_ctrl1, nt ? 1 : 0); + SET_V_G2_G3_EN(a_su_ctrl1, 0); /* Disallowed in order to be able to + * guarantee that T1 is handled + * correctly (xref6) */ + SET_V_B1_RX_EN(a_su_ctrl2, 1); + SET_V_B2_RX_EN(a_su_ctrl2, 1); + SET_V_SU_ACT(a_su_wr_sta, 3); /* activation */ + SET_V_SU_CLK_DLY(a_su_clk_dly, nt ? 0xC : 0xE); /* normal operation + * WARNING: if the + * interface is + * softconfigured, this + * should always be + * 0xC XXX */ + SET_V_ST_SMPL(a_su_clk_dly, nt ? 0x6 : 0x0); /* default value */ + + write_xhfc(x, R_SU_SEL, r_su_sel); + xhfc_waitbusy(x); + write_xhfc(x, A_SU_CTRL0, a_su_ctrl0); + write_xhfc(x, A_SU_CTRL1, a_su_ctrl1); + write_xhfc(x, A_SU_CTRL2, a_su_ctrl2); + write_xhfc(x, A_SU_CLK_DLY, a_su_clk_dly); + write_xhfc(x, A_SU_WR_STA, a_su_wr_sta); + xhfc_waitbusy(x); +} + +/* 2 MBit/s (C4IO is 4.096 MHz, 32 time slots): */ +#define V_PCM_DR_2M 0x00 + +/* 4 MBit/s (C4IO is 8.192 MHz, 64 time slots): */ +#define V_PCM_DR_4M 0x10 + +/* 8 MBit/s (C4IO is 16.384 MHz, 128 time slots): */ +#define V_PCM_DR_8M 0x20 + +/* configures PCM master mode +*/ +int xhfc_config_pcm(struct xhfc *xhfc, int master_or_slave) +{ + u8 r_pcm_md0 = 0; + + SET_V_F0_LEN(r_pcm_md0, 1); + + write_xhfc(xhfc, R_PCM_MD0, SET_V_PCM_IDX(r_pcm_md0, 0x9)); + /* use slow PCM clock adjust speed */ + write_xhfc(xhfc, R_PCM_MD1, M_PLL_ADJ | V_PCM_DR_2M); + /* NOTE: open drain on the PCM: add bit M_PCM_OD in R_PCM_MD1 + * We can't do that with the demo interface card for + * Megrez <-> XHFC EVB because Xavier did not managed to get + * SMD 1k R before soldering :P + */ + + if (master_or_slave == XHFC_PCM_MASTER) { + write_xhfc(xhfc, R_PCM_MD0, + SET_V_PCM_IDX(r_pcm_md0, 0xA)); + /* enable PCM bit clk for C2O pin */ + write_xhfc(xhfc, R_PCM_MD2, M_C2O_EN); + } else { + write_xhfc(xhfc, R_PCM_MD0, + SET_V_PCM_IDX(r_pcm_md0, 0xA)); + write_xhfc(xhfc, R_PCM_MD2, M_C2I_EN); + } + + /* this could maybe be done sooner, but right now I'm limiting + * the number of changes */ + write_xhfc(xhfc, R_PCM_MD0, SET_V_PCM_IDX(r_pcm_md0, 0x0) + | M_PCM_MD | M_C4_POL); + + return 0; +} + +#define debug_fz(fifo, prefix, buf) \ +do { \ +sprintf(buf, "%s(fifo %d): flen=%d, " \ + "zlen=%d", prefix, fifo, flen, \ + zlen); \ +} while (0) + +#define DEFINE_GET_LEN(F_or_Z) \ +static inline int \ +get_ ## F_or_Z ## len(struct xhfc* x) { \ +u8 _1, _2; \ +int len; \ + \ +_1 = read_xhfc(x, A_ ## F_or_Z ## 1); \ +_2 = read_xhfc(x, A_ ## F_or_Z ## 2); \ +len = _1 - _2; \ + \ +if (len < 0) \ + len += \ + (XHFC_ ## F_or_Z ## MAX - \ + XHFC_ ## F_or_Z ## MIN) + 1; \ + \ +return len; \ +} + +DEFINE_GET_LEN(F) +DEFINE_GET_LEN(Z) + +void xhfc_config_d_chan_on_fifo(struct xhfc *x, int fifo, int direction) +{ + u8 r_fifo, a_con_hdlc, a_channel, a_subch_cfg, a_inc_res_fifo; + r_fifo = a_con_hdlc = a_channel = a_subch_cfg = a_inc_res_fifo = 0x00; + + SET_V_FIFO_NUM(r_fifo, fifo); + + SET_V_IFF(a_con_hdlc, 1); /* inter frame fill with 1s */ + SET_V_HDLC_TRP(a_con_hdlc, 0); /* HDLC mode */ + SET_V_FIFO_IRQ(a_con_hdlc, 7); /* FIFO & IRQ enabled */ + SET_V_CH_FNUM(a_channel, fifo); /* chan number */ + SET_V_BIT_CNT(a_subch_cfg, 2); /* only two bits read or written */ + SET_V_RES_FIFO(a_inc_res_fifo, 1); /* reset FIFO */ + SET_V_RES_LOST(a_inc_res_fifo, 1); /* reset FIFO */ + SET_V_RES_FIFO_ERR(a_inc_res_fifo, 1); /* reset FIFO */ + + SET_V_DATA_FLOW(a_con_hdlc, 0); /* FIFO <-> ST/Up */ + + SET_V_FIFO_DIR(r_fifo, direction); + SET_V_CH_FDIR(a_channel, direction); + + write_xhfc(x, R_FIFO, r_fifo); + xhfc_waitbusy(x); + write_xhfc(x, A_CON_HDLC, a_con_hdlc); + write_xhfc(x, A_CHANNEL, a_channel); + write_xhfc(x, A_SUBCH_CFG, a_subch_cfg); + write_xhfc(x, A_INC_RES_FIFO, a_inc_res_fifo); + xhfc_waitbusy(x); +} + +void xhfc_config_b_chan_on_fifo(struct xhfc *x, int fifo, int slot, int direction) +{ + u8 r_fifo, a_con_hdlc, r_slot, a_sl_cfg; + r_fifo = a_con_hdlc = r_slot = a_sl_cfg = 0x00; + + SET_V_FIFO_DIR(r_fifo, direction); + SET_V_FIFO_NUM(r_fifo, fifo); + SET_V_REV(r_fifo, 1); + + SET_V_IFF(a_con_hdlc, 0); /* Ox7E as interframe fill -- not really used */ + SET_V_HDLC_TRP(a_con_hdlc, 1); /* transparent mode */ + SET_V_FIFO_IRQ(a_con_hdlc, 7); /* enable data transmission */ + SET_V_DATA_FLOW(a_con_hdlc, 6); /* '110': ST <-> PCM */ + + SET_V_SL_DIR(r_slot, direction); + SET_V_SL_NUM(r_slot, slot); + + SET_V_CH_SDIR(a_sl_cfg, direction); + SET_V_CH_SNUM(a_sl_cfg, fifo); + SET_V_ROUT(a_sl_cfg, 3); /* '11': receive data from STIO1, output to STIO2 */ + + write_xhfc(x, R_FIFO, r_fifo); + xhfc_waitbusy(x); + write_xhfc(x, A_CON_HDLC, a_con_hdlc); + write_xhfc(x, R_SLOT, r_slot); + write_xhfc(x, A_SL_CFG, a_sl_cfg); +} + +void xhfc_config_data_flow(struct xhfc* x) +{ + int i; + for (i = 0; i < SPANS_PER_CHIP; i++) { + /* HFC chan, PCM slot, direction */ + xhfc_config_b_chan_on_fifo(x, i * 4 + 0, i * 2 + 0, TRANSMIT); + xhfc_config_b_chan_on_fifo(x, i * 4 + 0, i * 2 + 0, RECEIVE); + xhfc_config_b_chan_on_fifo(x, i * 4 + 1, i * 2 + 1, TRANSMIT); + xhfc_config_b_chan_on_fifo(x, i * 4 + 1, i * 2 + 1, RECEIVE); + + xhfc_config_d_chan_on_fifo(x, i * 4 + 2, TRANSMIT); + xhfc_config_d_chan_on_fifo(x, i * 4 + 2, RECEIVE); + } +} + +/** +* hdlc_signal_complete() - Signal dahdi that we have a complete frame. +* +* @xhfc_span: The span which received the frame. +* @stat: The frame status byte from the XHFC controller. +* +*/ +static void hdlc_signal_complete(struct xhfc_span *xhfc_span, u8 stat) +{ + if (stat != 0x00) { + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME "(port %d) STAT=0x%02x indicates " + "frame problem: %s\n", portno(xhfc_span), + stat, + (0xff == stat) ? "HDLC Abort" : "Bad FCS"); + } + + dahdi_hdlc_abort(xhfc_span->sigchan, (0xff == stat) ? + DAHDI_EVENT_ABORT : DAHDI_EVENT_BADFCS); + } else { + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME + "(port %d) Frame " /*"%d" */ "is good!\n", + portno(xhfc_span) + /*, xhfc_span->frames_in */ ); + } + dahdi_hdlc_finish(xhfc_span->sigchan); + } +} + +/* + * Inner loop for D-channel receive function. Retrieves HDLC data from the + * hardware. If the hardware indicates that the frame is complete, we check + * the HDLC engine's STAT byte and update DAHDI as needed. + * + * Returns the number of HDLC frames left in the FIFO. */ +static int hdlc_rx_frame(struct xhfc_span *xhfc_span) +{ + char debugbuf[MAX(256, HDLC_BUF_LEN * 3 + 1)]; + int dbglen; + + int fifo, i, j, k, zleft; + int zlen, flen; + unsigned char buf[HDLC_BUF_LEN]; + struct xhfc *x = xhfc_span->xhfc; + + fifo = dchan_fifo(xhfc_span); + + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): start\n", + __func__, fifo); + + xhfc_selfifo(x, fifo, RECEIVE); + + flen = get_Flen(x); + zlen = get_Zlen(x); + + debug_fz(fifo, __func__, debugbuf); + + if (!flen && !zlen) { + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": %s, nothing to receive (%ld)\n", + debugbuf, xhfc_span->non_rx_cnt); + xhfc_span->non_rx_cnt++; + return 0; + } + xhfc_span->non_rx_cnt = 0; + + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); + + /* if we have at least one complete frame, increment zleft to include + * status byte */ + zleft = zlen; + if (flen) + zleft++; + + do { + j = zleft > HDLC_BUF_LEN ? HDLC_BUF_LEN : zleft; + + for (i = 0; i < j; i++) + buf[i] = read_xhfc(x, A_FIFO_DATA); + + /* don't send STAT byte to DAHDI */ + k = j; + if (xhfc_span->sigchan) { + if ((j != HDLC_BUF_LEN) && flen) + k--; + if (k) + dahdi_hdlc_putbuf(xhfc_span->sigchan, buf, k); + } + + zleft -= j; + + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": transmitted %d bytes to dahdi, " + "zleft=%d\n", k, zleft); + + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + dbglen = 0; + for (i = 0; i < j; i++) + dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); + debugbuf[dbglen] = '\0'; + + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): " + "zlen=%d, zleft=%d: %s\n", __func__, + fifo, zlen, zleft, debugbuf); + } + } while (zleft > 0); + + /* Frame received, increment F2 */ + if (flen) + xhfc_inc_f(x); + + /* If this channel is not configured with a signalling span we don't + * need to notify the rest of dahdi about this frame. */ + if (!xhfc_span->sigchan) { + if (DBG_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": %s(fifo %d): flen %d, early end\n", + __func__, fifo, flen); + return flen; + } + + if (flen) + hdlc_signal_complete(xhfc_span, buf[i - 1]); + + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): flen=%d end\n", + __func__, fifo, flen); + + return flen; +} + +static uint frames_out; +/* +* Takes one blob of data from DAHDI and shoots it out to the hardware. The +* blob may or may not be a complete HDLC frame. If it isn't, the rest will be +* pulled during the next timer interrupt. +* Returns nonzero if there is still data to send in the current HDLC frame. +*/ +static int hdlc_tx_frame(struct xhfc_span *xhfc_span) +{ + struct xhfc *x = xhfc_span->xhfc; + struct dahdi_span *dahdi_span = &xhfc_span->span; + int res, i, fifo; + int zlen; + int flen = -1; + unsigned char buf[HDLC_BUF_LEN]; + unsigned int size = ARRAY_SIZE(buf); + char debugbuf[MAX(256, HDLC_BUF_LEN * 3 + 1)]; + int dbglen; + + /* ignoring TE red alarms: if TE and we are in alarm, restart the + * S/T state machine... */ + if (!xhfc_span->nt && (xhfc_span->span.alarms != 0)) { + activate_request(xhfc_span); + } + + fifo = dchan_fifo(xhfc_span); + res = dahdi_hdlc_getbuf(xhfc_span->sigchan, buf, &size); + + xhfc_selfifo(x, fifo, TRANSMIT); + + zlen = get_Zlen(x); + debug_fz(fifo, __func__, debugbuf); + + /* TODO: check zlen, etc. */ + if ((XHFC_ZMAX - zlen) < size) { + static int arg; + printk(KERN_INFO DRIVER_NAME ": arg (%d), zlen (%d) < what we " + "grabbed from DAHDI (%d)!\n", ++arg, zlen, size); + size = zlen; + dahdi_hdlc_abort(xhfc_span->sigchan, DAHDI_EVENT_OVERRUN); + } + + if (size > 0) { + + for (i = 0; i < size; i++) + write_xhfc(x, A_FIFO_DATA, buf[i]); + /* + * If we got a full frame from DAHDI, increment F and + * decrement our HDLC pending counter. */ + if (res != 0) { + frames_out++; + xhfc_inc_f(x); + atomic_dec(&xhfc_span->hdlc_pending); + } + } + + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); + + dbglen = 0; + for (i = 0; i < size; i++) + dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); + debugbuf[dbglen] = '\0'; + + printk(KERN_INFO DRIVER_NAME + ": hdlc_tx_frame(span %d): DAHDI gave %d " + "bytes for FIFO %d (res = %d): %s\n", + dahdi_span->spanno, + size, fifo, res, debugbuf); + + if (size && res != 0) + printk(KERN_INFO DRIVER_NAME + ": Transmitted frame %d on span %d\n", + frames_out - 1, dahdi_span->spanno); + } + + return !res; +} + +/* DAHDI calls this when it has data it wants to send to the HDLC controller */ +void xhfc_hdlc_hard_xmit(struct dahdi_chan *chan) +{ + struct dahdi_span *dahdi_span = chan->span; + struct xhfc_span *xhfc_span = + container_of(dahdi_span, struct xhfc_span, span); + + if ((DBG_FOPS || DBG_HDLC) && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s on chan %s (%i/%i), " + "span=%i (sigchan=%p, chan=%p): %d+1 frames\n", + __func__, chan->name, chan->channo, + chan->chanpos, dahdi_span->spanno, + xhfc_span->sigchan, chan, + atomic_read(&xhfc_span->hdlc_pending)); + + /* Increment the hdlc_pending counter and trigger hdlc_tx_frame */ + if (xhfc_span->sigchan == chan) + atomic_inc(&xhfc_span->hdlc_pending); +} + +/***************************************************************************** + * Interrupt handler, does all sort of stuff, some of which should prolly be * + * scheduled in a tasklet instead * + *****************************************************************************/ + +#define fifo_test(reg, fifonum, dir) (reg[fifonum/4] & (1 << (((fifonum % 4) * 2) + dir))) + +irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) +{ + + struct xhfc_pi *pi = dev_id; + struct xhfc *xhfc; + + int i; + u8 r_su_irq; + u8 misc_irq; + u8 fifo_irq[SPANS_PER_CHIP]; + u8 fifo_fill[SPANS_PER_CHIP]; + + (void) ptregs; + + xhfc = &pi->xhfc; + + /* IRQs for other HW with shared IRQ or spurious + * XXX for XiVO OpenHardware we should not share IRQ! */ + if (!(read_xhfc(xhfc, R_IRQ_OVIEW))) + return IRQ_NONE; + + /* reset IRQ source */ + misc_irq = read_xhfc(xhfc, R_MISC_IRQ); + + if (xhfc->running) { + /* check for Timer IRQ */ + if (misc_irq & M_TI_IRQMSK) + xhfc->ticks++; + + for(i = 0; i < SPANS_PER_CHIP; i++) { + fifo_irq[i] = read_xhfc(xhfc, R_FIFO_BL0_IRQ + i); + fifo_fill[i] = read_xhfc(xhfc, R_FILL_BL0 + i); + } + + for (i = 0; i < SPANS_PER_CHIP; i++) { + struct xhfc_span* s = &xhfc->spans[i]; + + if ((s->span.flags & DAHDI_FLAG_RUNNING) && s->sigchan && + s->span.alarms == DAHDI_ALARM_NONE) { + + /* No need to loop, makes no sense to receive + * more than one HDLC frame per second. + */ + if ( fifo_test(fifo_irq, dchan_fifo(s), RECEIVE) || + fifo_test(fifo_fill, dchan_fifo(s), RECEIVE)) + + hdlc_rx_frame(s); + + if (atomic_read(&s->hdlc_pending)) + hdlc_tx_frame(s); +#ifdef AUDIO + /* Put in readchunk chunk _previously_ retrieved + * from icp soft. + * We can't update it at icp level right now, + * because it has been written by trippy monkeys + * and it would probably be a very bad idea to + * try to call it from hardirq context. + * (look at ixOsalMutexLock ... :/ ) + */ + xivo_tdm_receive(pi->tdm_port, i*2 + 0, + s->chans[0]->readchunk); + xivo_tdm_receive(pi->tdm_port, i*2 + 1, + s->chans[1]->readchunk); + + dahdi_receive(&s->span); + dahdi_transmit(&s->span); + dahdi_ec_span(&s->span); + + xivo_tdm_transmit(pi->tdm_port, i*2 + 0, + s->chans[0]->writechunk); + xivo_tdm_transmit(pi->tdm_port, i*2 + 1, + s->chans[1]->writechunk); +#endif + } + } + +#ifdef AUDIO + xivo_tdm_tick(pi->tdm_port); +#endif + + r_su_irq = read_xhfc(xhfc, R_SU_IRQ); + + for (i = 0; i < SPANS_PER_CHIP; i++) { + handle_st_timers(&xhfc->spans[i]); + if (r_su_irq & (1 << i) || 2 == xhfc->ticks /* bootstrap XXX WTF*/) + handle_state_change(&xhfc->spans[i]); + } + } + + return IRQ_HANDLED; +} + + +/*****************************************************/ +/* disable all interrupts by disabling M_GLOB_IRQ_EN */ +/*****************************************************/ +static void disable_interrupts(struct xhfc * xhfc) +{ + printk(KERN_INFO "%s %s\n", xhfc->name, __func__); + + write_xhfc(xhfc, R_IRQ_CTRL, 0); + read_xhfc(xhfc, R_CHIP_ID); + mb(); + + set_mb(xhfc->running, 0); +} + + +/******************************************/ +/* start interrupt and set interrupt mask */ +/******************************************/ +static void enable_interrupts(struct xhfc * xhfc) +{ + u8 r_irq_ctrl = 0; + printk(KERN_INFO "%s %s\n", xhfc->name, __func__); + + set_mb(xhfc->running, 1); + + /* timer interrupt every 1 ms */ + write_xhfc(xhfc, R_TI_WD, 0x02); + write_xhfc(xhfc, R_MISC_IRQMSK, M_TI_IRQMSK); + + /* clear all pending interrupts bits */ + read_xhfc(xhfc, R_MISC_IRQ); + read_xhfc(xhfc, R_SU_IRQ); + read_xhfc(xhfc, R_FIFO_BL0_IRQ); + read_xhfc(xhfc, R_FIFO_BL1_IRQ); + read_xhfc(xhfc, R_FIFO_BL2_IRQ); + read_xhfc(xhfc, R_FIFO_BL3_IRQ); + + /* enable global interrupts */ + SET_V_GLOB_IRQ_EN(r_irq_ctrl, 1); + SET_V_FIFO_IRQ_EN(r_irq_ctrl, 1); + write_xhfc(xhfc, R_IRQ_CTRL, r_irq_ctrl); +} + + +/***********************************/ +/* initialise the XHFC ISDN Chip */ +/* return 0 on success. */ +/***********************************/ +int xhfc_collect_chip_id(struct xhfc * xhfc) +{ + u8 chip_id = read_xhfc(xhfc, R_CHIP_ID); + switch (chip_id) { + case CHIP_ID_1SU: + case CHIP_ID_2SU: + case CHIP_ID_2S4U: + case CHIP_ID_4SU: + printk(KERN_INFO "%s ChipID: 0x%x\n", + xhfc->name, chip_id); + return 0; + } + + printk(KERN_ERR "%s %s: unkown Chip ID 0x%x\n", + xhfc->name, __func__, chip_id); + return -EIO; +} + +void xhfc_hard_reset(void) +{ +#ifdef USE_GPIO + gpio_set_direction(reset_gpio, GPIO_OUTPUT); + gpio_set_to_gpio(reset_gpio); + gpio_set_level(reset_gpio, GPIO_LOW); + msleep(1); + gpio_set_level(reset_gpio, GPIO_HIGH); +#endif +} + +#if 0 +void configure_port(int port, int nt, int lineterm) +{ + gpio_set_direction(lineterm_gpio, GPIO_OUTPUT); + gpio_set_to_gpio(lineterm_gpio); + gpio_set_direction(ntte_gpio, GPIO_OUTPUT); + gpio_set_to_gpio(ntte_gpio); + gpio_set_level(lineterm_gpio, lineterm); + gpio_set_level(ntte_gpio, nt); +} +#endif + +void xhfc_init_and_configure(struct xhfc* x) +{ + u8 r_fifo_thres = 0; + /* In DAHDI's driver's this part is "stage 1" */ + xhfc_reset(x); + + /* Make sure interrupts disabled */ + disable_interrupts(x); + + /* "stage 2" */ + xhfc_config_pcm(x, XHFC_PCM_MASTER); + + /* Now we need to setup the flow controller and stuff */ + xhfc_config_data_flow(x); + + SET_V_THRES_RX(r_fifo_thres, 2); + SET_V_THRES_TX(r_fifo_thres, 2); + write_xhfc(x, R_FIFO_THRES, r_fifo_thres); +} + +static void xhfc_span_set_ntte(struct xhfc_span* s, int ntte) +{ + s->nt = !!ntte; + s->span.spantype = ntte ? "NT" : "TE"; +} + +int xhfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) +{ + struct xhfc_span *xhfc_span; + struct xhfc *xhfc; + int term; + + xhfc_span = container_of(span, struct xhfc_span, span); + xhfc = xhfc_span->xhfc; + + xhfc_span_set_ntte(xhfc_span, lc->lineconfig & DAHDI_CONFIG_NTTE); /* xref2 */ + + term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0; + + printk(KERN_INFO DRIVER_NAME ": Configuring port %d span %d in %s mode" + " with termination resistance %s\n", + portno(xhfc_span), span->spanno, + xhfc_span->nt ? "NT" : "TE", + term ? "ENABLED" : "DISABLED"); + + /* TODO conf hardware interface w/ GPIO */ + xhfc_config_st(xhfc, xhfc_span->port, xhfc_span->nt); + + printk(KERN_INFO DRIVER_NAME ": WARNING: This driver can't configure " + "the ports yet, expect problems if port %d isn't " + "configured in %s mode\n", + portno(xhfc_span), xhfc_span->nt ? "NT" : "TE"); + + if (lc->sync < 0) { + printk(KERN_INFO DRIVER_NAME + ": Span %d has invalid sync priority (%d), " + "removing from sync source list\n", + span->spanno, lc->sync); + lc->sync = 0; + } + + if (xhfc_span->nt && lc->sync) { + printk(KERN_INFO DRIVER_NAME + ": NT Spans cannot be timing sources. " + "Span %d requested to be timing source of " + "priority %d. Changing priority to 0\n", + span->offset, lc->sync); + lc->sync = 0; + } + + start_state_machine(xhfc_span); + + return 0; +} + +int xhfc_chanconfig(struct dahdi_chan *chan, int sigtype) +{ + int alreadyrunning; + struct xhfc_span *xhfc_span = container_of(chan->span, struct xhfc_span, span); + int res; + + alreadyrunning = xhfc_span->span.flags & DAHDI_FLAG_RUNNING; + + if (DBG_FOPS) + printk(KERN_INFO DRIVER_NAME + ": %s channel %d (%s) sigtype %08x\n", + alreadyrunning ? "Reconfigured" : "Configured", + chan->channo, chan->name, sigtype); + + switch (sigtype) { + case DAHDI_SIG_HARDHDLC: + /* xref1 */ + if (DBG_FOPS) + printk(KERN_INFO DRIVER_NAME + ": Configuring hardware HDLC on %s\n", + chan->name); + xhfc_span->sigchan = chan; + atomic_set(&xhfc_span->hdlc_pending, 0); + res = 0; + break; + case DAHDI_SIG_HDLCFCS: + printk(KERN_INFO DRIVER_NAME ": HDLCFCS not supported\n"); + res = -ENOSYS; + break; + case DAHDI_SIG_HDLCNET: + printk(KERN_INFO DRIVER_NAME ": HDLCNET not supported\n"); + res = -ENOSYS; + break; + case DAHDI_SIG_HDLCRAW: + printk(KERN_INFO DRIVER_NAME ": HDLCRAW not supported\n"); + res = -ENOSYS; + break; + default: + res = 0; + break; + }; + + return res; +} + +static int xhfc_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) +{ + return -ENOTTY; +} + +static int xhfc_span_startup(struct dahdi_span* s) +{ + struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); + activate_request(xhfc_span); + return 0; +} + +static int xhfc_span_shutdown(struct dahdi_span* s) +{ + struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); + deactivate_request(xhfc_span); + return 0; +} + +static const struct dahdi_span_ops xhfc_span_ops = { + .owner = THIS_MODULE, + .spanconfig = xhfc_spanconfig, + .chanconfig = xhfc_chanconfig, + .startup = xhfc_span_startup, + .shutdown = xhfc_span_shutdown, + .ioctl = xhfc_ioctl, + .hdlc_hard_xmit = xhfc_hdlc_hard_xmit, +}; + +/************************************************************************ + * Responsible for initializing the xhfc_span and dahdi_span structures * + ************************************************************************/ +void init_spans(struct xhfc* x) +{ + int i, j; + struct xhfc_span *xhfc_span; + struct dahdi_span *dahdi_span; + struct dahdi_chan *chan; + +/* for each span on the card */ + for (i = 0; i < SPANS_PER_CHIP; i++) { + + xhfc_span = &x->spans[i]; + dahdi_span = &xhfc_span->span; + + xhfc_span->xhfc = x; + xhfc_span->port = i; + + xhfc_span->sigchan = NULL; /* conf'd in chanconfig (xref1) */ + xhfc_span_set_ntte(xhfc_span, ntte & (1 << i)); /* reconf'd in spanconfig (xref2) */ + + /* All the timer stuff is done in the timer and state + * functions, not here. */ + + dahdi_span->ops = &xhfc_span_ops; + dahdi_span->chans = xhfc_span->chans; + dahdi_span->irq = x->pi->pci_dev->irq; + dahdi_span->offset = i; + dahdi_span->channels = CHANS_PER_SPAN; + dahdi_span->flags = 0; + dahdi_span->deflaw = DAHDI_LAW_ALAW; + dahdi_span->linecompat = + DAHDI_CONFIG_TERM | DAHDI_CONFIG_NTTE | + DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS ; + + sprintf(dahdi_span->name, "XHFC/%d", i+1); + sprintf(dahdi_span->desc, "XHFC port %d", i+1); + dahdi_span->manufacturer = "Avencall"; + dahdi_copy_string(dahdi_span->devicetype, "XHFC-4SU", + sizeof(dahdi_span->devicetype)); + sprintf(dahdi_span->location, "PCI Bus %02d Slot %02d", + x->pi->pci_dev->bus->number, + PCI_SLOT(x->pi->pci_dev->devfn) + 1); + + dahdi_span->alarms = DAHDI_ALARM_RED; + + + init_waitqueue_head(&dahdi_span->maintq); /* kinda everyone does this */ + + /* now initialize each channel in the span */ + for (j=0; j < CHANS_PER_SPAN; j++) { + xhfc_span->chans[j] = &xhfc_span->_chans[j]; + chan = xhfc_span->chans[j]; + chan->pvt = x; + + sprintf(chan->name, "XHFC/%d/%d", i + 1, j + 1); + + if (j == 2) { + chan->sigcap = DAHDI_SIG_HARDHDLC; + } else { + chan->sigcap = DAHDI_SIG_CLEAR | DAHDI_SIG_DACS; + } + chan->chanpos = j + 1; + chan->writechunk = (void *)(xhfc_span->writechunk + j * DAHDI_CHUNKSIZE); + chan->readchunk = (void *)(xhfc_span->readchunk + j * DAHDI_CHUNKSIZE); + } + } +} + +void release_card_irq(struct xhfc_pi * pi) +{ + disable_interrupts(&pi->xhfc); + free_irq(pi->irq, pi); +} + +static const struct pci_device_id tlp_leb_pci_tbl[] = { + { 0x8086, 0x503d, PCI_ANY_ID, PCI_ANY_ID, }, /* Intel Tolapai LEB controler */ + { } +}; +MODULE_DEVICE_TABLE(pci, tlp_leb_pci_tbl); + +static struct pci_driver xhfc_driver = { + .name = DRIVER_NAME, + .id_table = tlp_leb_pci_tbl, + .probe = xhfc_init_one, + .remove = __devexit_p(xhfc_remove_one), +// .shutdown = xhfc_shutdown, +}; + +/* pci.txt: called from process context */ +int __devinit xhfc_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int span; + struct xhfc_pi * pi; + unsigned long base, size; + int rc = -ENOMEM; + + printk(KERN_DEBUG "entering xhfc_init_one\n"); + + + /**************** + * Memory alloc * + ****************/ + + pi = kzalloc(sizeof(struct xhfc_pi), GFP_KERNEL); + if (pi == NULL) + goto err_alloc; + + sprintf(pi->name, "%s", DRIVER_NAME); /* ? */ + + printk(KERN_INFO "%s %s: adapter '%s' found on PCI bus %02x dev %02x\n", + pi->name, __func__, pi->name, + pdev->bus->number, pdev->devfn); + + + /************ + * PCI init * + ************/ + + rc = pci_enable_device(pdev); + + if (rc) + goto err_enable_device; + + printk(KERN_DEBUG "pci_enable_device succeeded\n"); + + rc = pci_request_regions(pdev, DRIVER_NAME); + if (rc) + goto err_request_regions; + + rc = -ENOMEM; + + base = pci_resource_start(pdev, LEB_CSRBAR); + size = pci_resource_len(pdev, LEB_CSRBAR); + pi->regs = ioremap(base, size); + if (!pi->regs) + goto err_ioremap_csrbar; + + base = pci_resource_start(pdev, LEB_MMBAR); + size = pci_resource_len(pdev, LEB_MMBAR); + pi->cs_n0 = ioremap(base, size); + if (!pi->cs_n0) + goto err_ioremap_mmbar; + + pci_set_drvdata(pdev, pi); + + + /************* + * Hard init * + *************/ + + xhfc_hard_reset(); + + if (exit_after_reset) { + rc = -EINVAL; + goto exit_after_reset; + } + + leb_init(pi); + + +#ifdef AUDIO + /************* + * TDM alloc * + *************/ + + pi->tdm_port = xivo_tdm_get_port(XIVO_XHFC_TDM_PORT); + if (!pi->tdm_port) { + rc = -EBUSY; + goto err_tdm_get_port; + } +#endif + + /******************** + * XHFC struct init * + ********************/ + + pi->pci_dev = pdev; + pi->xhfc.pi = pi; + + /* only adress one xhfc per PI */ + pi->xhfc.name = pi->name; + + /* init interrupt engine */ + rc = pi->irq = acpi_register_gsi( + IRQ_TLP_GPIO_24, + ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); + if (rc < 0) + goto err_acpi_register; + + + /******** + * test * + ********/ + + rc = xhfc_collect_chip_id(&pi->xhfc); + if (rc) + goto err_collect_chip_id; + + + /*************** + * OK let's go * + ***************/ + + card_cnt++; + + if ((rc = request_irq(pi->irq, &xhfc_interrupt, 0, "XHFC", pi))) { + printk(KERN_WARNING "%s %s: couldn't get interrupt %d\n", + pi->name, __func__, pi->irq); + goto err_request_irq; + } + + init_spans(&pi->xhfc); + + xhfc_init_and_configure(&pi->xhfc); +#ifdef AUDIO + /* TDM started on the XHFC side, XHFC is MASTER */ + /* Now it's possible to start the TDM bus on the EP80579 side, as SLAVE: */ + if ((rc = xivo_tdm_config_port(pi->tdm_port, XHFC_MEGREZ_PROTO_XIVO_CONFIG)) < 0) { + printk(KERN_ERR "%s %s: xivo_tdm_config_port failed (err=%d)\n", pi->name, __func__, rc); + goto err_tdm_config_port; + } +#endif + + for (span = 0; span < SPANS_PER_CHIP; span++) + if ((rc = dahdi_register(&pi->xhfc.spans[span].span, /*prefmaster*/ 1)) < 0) { + printk(KERN_WARNING "%s %s: couldn't register spans\n", pi->name, __func__); + goto err_in_dahdi_register; + } + + enable_interrupts(&pi->xhfc); + +#ifdef AUDIO + xivo_tdm_start_chans(pi->tdm_port, + /* timeslots 0->7 */ 0xFF, + NULL); +#endif + + return 0; + +err_in_dahdi_register: + for (span--; span >= 0; span--) + dahdi_unregister(&pi->xhfc.spans[span].span); +#ifdef AUDIO +err_tdm_config_port: +#endif + free_irq(pi->irq, pi); +err_request_irq: +err_collect_chip_id: + //acpi_unregister_gsi(IRQ_TLP_GPIO_30); /* symbol doesn't exist??? */ +err_acpi_register: +#ifdef AUDIO + xivo_tdm_put_port(pi->tdm_port); +err_tdm_get_port: +#endif +exit_after_reset: + iounmap(pi->cs_n0); +err_ioremap_mmbar: + iounmap(pi->regs); +err_ioremap_csrbar: + pci_release_regions(pdev); +err_request_regions: + pci_disable_device(pdev); +err_enable_device: + kfree(pi); +err_alloc: + return rc; +} + +void __devexit xhfc_remove_one(struct pci_dev *pdev) +{ + int i; + struct xhfc_pi *pi; + + pi = pci_get_drvdata(pdev); + + if (DBG) + printk(KERN_INFO "%s %s: removing card\n", + pi->name, __func__); + + for (i = 0; i < SPANS_PER_CHIP; i++) + dahdi_unregister(&pi->xhfc.spans[i].span); + + release_card_irq(pi); + + card_cnt--; + + iounmap(pi->regs); + pi->regs = NULL; + iounmap(pi->cs_n0); + pi->cs_n0 = NULL; + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(pi); + + printk(KERN_DEBUG "%s: bye-bye\n", __func__); +} + +/***************/ +/* Module init */ +/***************/ +static int __init xhfc_init(void) +{ + int err; + + if (DBG) + printk(KERN_INFO DRIVER_NAME " driver Rev. %s\n", xhfc_rev); + + err = dahdi_pci_module(&xhfc_driver); + if (err < 0) + goto out; + + /* XXX fail with error if no cards detected */ + + return 0; + + out: + return (err); +} + +static void __exit xhfc_cleanup(void) +{ + pci_unregister_driver(&xhfc_driver); + if (DBG) + printk(KERN_INFO "%s: driver removed\n", __func__); +} + +module_init(xhfc_init); +module_exit(xhfc_cleanup); + diff --git a/xhfc/xhfc.c b/xhfc/xhfc.c deleted file mode 100644 index c2c9a02..0000000 --- a/xhfc/xhfc.c +++ /dev/null @@ -1,1202 +0,0 @@ -#include -#include -#include -#include -#include - -#ifdef USE_GPIO -#include -#endif - -#include "xhfc24sucd.h" -#include "xhfc.h" -#include "xhfc_leb.h" - -static const char xhfc_rev[] = "$Revision: 1.22 $"; -static int card_cnt = 0; - -MODULE_LICENSE("GPL"); - -uint debug = 0; -uint dbg_spanfilter = 0xFFFFFFFF; -int exit_after_reset = 0; - -uint ntte = 0x3; - -#ifdef USE_GPIO -static uint reset_gpio = 21; -#endif - -int softconf = 0; - -module_param(debug, uint, S_IRUGO | S_IWUSR); -module_param(dbg_spanfilter, uint, S_IRUGO | S_IWUSR); -module_param(softconf, bool, S_IRUGO); -module_param(ntte, uint, S_IRUGO); -module_param(exit_after_reset, bool, S_IRUGO); -#ifdef USE_GPIO -module_param(reset_gpio, uint, S_IRUGO); -#endif - -MODULE_PARM_DESC(debug, "Debug bitfield:\n" - "\t0: general\n" - //"\t2: verbose register access, only if DEBUG is defined\n" - "\t3: file operations\n" - "\t4: (not used, echo canceller)\n" - "\t5: ST state\n" - "\t6: HDLC\n" - "\t7: HDLC (verbose)\n" - "\t8: timing\n" - "\t9: alarms\n"); -MODULE_PARM_DESC(dbg_spanfilter, "bitfield, filter debug info by span."); -MODULE_PARM_DESC(ntte, "bitfield, configuration of the physical ports. ex: 0x3 = 0 NT, 1 NT, 2 TE, 3 TE."); -MODULE_PARM_DESC(softconf, "Configure the S/T port line interface in software."); -#ifdef USE_GPIO -MODULE_PARM_DESC(reset_gpio, "Reset the XHFC using this GPIO"); -#endif -MODULE_PARM_DESC(exit_after_reset, "Exit after hard reset"); - -#ifdef AUDIO -#define RX_HISTO_NB 16 -static int rx_histo[RX_HISTO_NB]; -#endif - -void xhfc_waitbusy(struct xhfc *xhfc) -{ - while (read_xhfc(xhfc, R_STATUS) & M_BUSY) - cpu_relax(); -} - -void xhfc_selfifo(struct xhfc *xhfc, int fifo, int receive) -{ - u8 r_fifo = 0x00; - SET_V_FIFO_NUM(r_fifo, fifo); - SET_V_FIFO_DIR(r_fifo, receive); - write_xhfc(xhfc, R_FIFO, r_fifo); - xhfc_waitbusy(xhfc); -} - -void xhfc_inc_f(struct xhfc *xhfc) -{ - write_xhfc(xhfc, A_INC_RES_FIFO, M_INC_F); - xhfc_waitbusy(xhfc); -} - -static inline void xhfc_resetfifo(struct xhfc *xhfc) -{ - write_xhfc(xhfc, A_INC_RES_FIFO, M_RES_FIFO | M_RES_FIFO_ERR); - xhfc_waitbusy(xhfc); -} - -int xhfc_reset(struct xhfc *xhfc) -{ - int timeout = 0x2000; - - /* software reset to enable R_FIFO_MD setting */ - write_xhfc(xhfc, R_CIRM, M_SRES); - udelay(5); - write_xhfc(xhfc, R_CIRM, 0); - - while ((read_xhfc(xhfc, R_STATUS) & (M_BUSY | M_PCM_INIT)) - && (timeout)) { - timeout--; - cpu_relax(); - } - - if (!(timeout)) { - printk(KERN_ERR - "%s %s: initialization sequence could not finish\n", - xhfc->pi->name, __func__); - return -EIO; - } - - return 0; -} - -void xhfc_config_st(struct xhfc *x, int port, int nt) -{ - u8 r_su_sel, a_su_ctrl0, a_su_ctrl1, a_su_ctrl2, a_su_wr_sta, a_su_clk_dly; - r_su_sel = a_su_ctrl0 = a_su_ctrl1 = a_su_ctrl2 = a_su_wr_sta = a_su_clk_dly = 0x00; - SET_V_SU_SEL(r_su_sel, port); - SET_V_SU_MD(a_su_ctrl0, !!nt); - SET_V_B1_TX_EN(a_su_ctrl0, 1); - SET_V_B2_TX_EN(a_su_ctrl0, 1); - SET_V_ST_E_IGNO(a_su_ctrl1, nt ? 1 : 0); - SET_V_G2_G3_EN(a_su_ctrl1, 0); /* Disallowed in order to be able to - * guarantee that T1 is handled - * correctly (xref6) */ - SET_V_B1_RX_EN(a_su_ctrl2, 1); - SET_V_B2_RX_EN(a_su_ctrl2, 1); - SET_V_SU_ACT(a_su_wr_sta, 3); /* activation */ - SET_V_SU_CLK_DLY(a_su_clk_dly, nt ? 0xC : 0xE); /* normal operation - * WARNING: if the - * interface is - * softconfigured, this - * should always be - * 0xC XXX */ - SET_V_ST_SMPL(a_su_clk_dly, nt ? 0x6 : 0x0); /* default value */ - - write_xhfc(x, R_SU_SEL, r_su_sel); - xhfc_waitbusy(x); - write_xhfc(x, A_SU_CTRL0, a_su_ctrl0); - write_xhfc(x, A_SU_CTRL1, a_su_ctrl1); - write_xhfc(x, A_SU_CTRL2, a_su_ctrl2); - write_xhfc(x, A_SU_CLK_DLY, a_su_clk_dly); - write_xhfc(x, A_SU_WR_STA, a_su_wr_sta); - xhfc_waitbusy(x); -} - -/* 2 MBit/s (C4IO is 4.096 MHz, 32 time slots): */ -#define V_PCM_DR_2M 0x00 - -/* 4 MBit/s (C4IO is 8.192 MHz, 64 time slots): */ -#define V_PCM_DR_4M 0x10 - -/* 8 MBit/s (C4IO is 16.384 MHz, 128 time slots): */ -#define V_PCM_DR_8M 0x20 - -/* configures PCM master mode -*/ -int xhfc_config_pcm(struct xhfc *xhfc, int master_or_slave) -{ - u8 r_pcm_md0 = 0; - - SET_V_F0_LEN(r_pcm_md0, 1); - - write_xhfc(xhfc, R_PCM_MD0, SET_V_PCM_IDX(r_pcm_md0, 0x9)); - /* use slow PCM clock adjust speed */ - write_xhfc(xhfc, R_PCM_MD1, M_PLL_ADJ | V_PCM_DR_2M); - /* NOTE: open drain on the PCM: add bit M_PCM_OD in R_PCM_MD1 - * We can't do that with the demo interface card for - * Megrez <-> XHFC EVB because Xavier did not managed to get - * SMD 1k R before soldering :P - */ - - if (master_or_slave == XHFC_PCM_MASTER) { - write_xhfc(xhfc, R_PCM_MD0, - SET_V_PCM_IDX(r_pcm_md0, 0xA)); - /* enable PCM bit clk for C2O pin */ - write_xhfc(xhfc, R_PCM_MD2, M_C2O_EN); - } else { - write_xhfc(xhfc, R_PCM_MD0, - SET_V_PCM_IDX(r_pcm_md0, 0xA)); - write_xhfc(xhfc, R_PCM_MD2, M_C2I_EN); - } - - /* this could maybe be done sooner, but right now I'm limiting - * the number of changes */ - write_xhfc(xhfc, R_PCM_MD0, SET_V_PCM_IDX(r_pcm_md0, 0x0) - | M_PCM_MD | M_C4_POL); - - return 0; -} - -#define debug_fz(fifo, prefix, buf) \ -do { \ -sprintf(buf, "%s(fifo %d): flen=%d, " \ - "zlen=%d", prefix, fifo, flen, \ - zlen); \ -} while (0) - -#define DEFINE_GET_LEN(F_or_Z) \ -static inline int \ -get_ ## F_or_Z ## len(struct xhfc* x) { \ -u8 _1, _2; \ -int len; \ - \ -_1 = read_xhfc(x, A_ ## F_or_Z ## 1); \ -_2 = read_xhfc(x, A_ ## F_or_Z ## 2); \ -len = _1 - _2; \ - \ -if (len < 0) \ - len += \ - (XHFC_ ## F_or_Z ## MAX - \ - XHFC_ ## F_or_Z ## MIN) + 1; \ - \ -return len; \ -} - -DEFINE_GET_LEN(F) -DEFINE_GET_LEN(Z) - -void xhfc_config_d_chan_on_fifo(struct xhfc *x, int fifo, int direction) -{ - u8 r_fifo, a_con_hdlc, a_channel, a_subch_cfg, a_inc_res_fifo; - r_fifo = a_con_hdlc = a_channel = a_subch_cfg = a_inc_res_fifo = 0x00; - - SET_V_FIFO_NUM(r_fifo, fifo); - - SET_V_IFF(a_con_hdlc, 1); /* inter frame fill with 1s */ - SET_V_HDLC_TRP(a_con_hdlc, 0); /* HDLC mode */ - SET_V_FIFO_IRQ(a_con_hdlc, 7); /* FIFO & IRQ enabled */ - SET_V_CH_FNUM(a_channel, fifo); /* chan number */ - SET_V_BIT_CNT(a_subch_cfg, 2); /* only two bits read or written */ - SET_V_RES_FIFO(a_inc_res_fifo, 1); /* reset FIFO */ - SET_V_RES_LOST(a_inc_res_fifo, 1); /* reset FIFO */ - SET_V_RES_FIFO_ERR(a_inc_res_fifo, 1); /* reset FIFO */ - - SET_V_DATA_FLOW(a_con_hdlc, 0); /* FIFO <-> ST/Up */ - - SET_V_FIFO_DIR(r_fifo, direction); - SET_V_CH_FDIR(a_channel, direction); - - write_xhfc(x, R_FIFO, r_fifo); - xhfc_waitbusy(x); - write_xhfc(x, A_CON_HDLC, a_con_hdlc); - write_xhfc(x, A_CHANNEL, a_channel); - write_xhfc(x, A_SUBCH_CFG, a_subch_cfg); - write_xhfc(x, A_INC_RES_FIFO, a_inc_res_fifo); - xhfc_waitbusy(x); -} - -void xhfc_config_b_chan_on_fifo(struct xhfc *x, int fifo, int slot, int direction) -{ - u8 r_fifo, a_con_hdlc, r_slot, a_sl_cfg; - r_fifo = a_con_hdlc = r_slot = a_sl_cfg = 0x00; - - SET_V_FIFO_DIR(r_fifo, direction); - SET_V_FIFO_NUM(r_fifo, fifo); - SET_V_REV(r_fifo, 1); - - SET_V_IFF(a_con_hdlc, 0); /* Ox7E as interframe fill -- not really used */ - SET_V_HDLC_TRP(a_con_hdlc, 1); /* transparent mode */ - SET_V_FIFO_IRQ(a_con_hdlc, 7); /* enable data transmission */ - SET_V_DATA_FLOW(a_con_hdlc, 6); /* '110': ST <-> PCM */ - - SET_V_SL_DIR(r_slot, direction); - SET_V_SL_NUM(r_slot, slot); - - SET_V_CH_SDIR(a_sl_cfg, direction); - SET_V_CH_SNUM(a_sl_cfg, fifo); - SET_V_ROUT(a_sl_cfg, 3); /* '11': receive data from STIO1, output to STIO2 */ - - write_xhfc(x, R_FIFO, r_fifo); - xhfc_waitbusy(x); - write_xhfc(x, A_CON_HDLC, a_con_hdlc); - write_xhfc(x, R_SLOT, r_slot); - write_xhfc(x, A_SL_CFG, a_sl_cfg); -} - -void xhfc_config_data_flow(struct xhfc* x) -{ - int i; - for (i = 0; i < SPANS_PER_CHIP; i++) { - /* HFC chan, PCM slot, direction */ - xhfc_config_b_chan_on_fifo(x, i * 4 + 0, i * 2 + 0, TRANSMIT); - xhfc_config_b_chan_on_fifo(x, i * 4 + 0, i * 2 + 0, RECEIVE); - xhfc_config_b_chan_on_fifo(x, i * 4 + 1, i * 2 + 1, TRANSMIT); - xhfc_config_b_chan_on_fifo(x, i * 4 + 1, i * 2 + 1, RECEIVE); - - xhfc_config_d_chan_on_fifo(x, i * 4 + 2, TRANSMIT); - xhfc_config_d_chan_on_fifo(x, i * 4 + 2, RECEIVE); - } -} - -/** -* hdlc_signal_complete() - Signal dahdi that we have a complete frame. -* -* @xhfc_span: The span which received the frame. -* @stat: The frame status byte from the XHFC controller. -* -*/ -static void hdlc_signal_complete(struct xhfc_span *xhfc_span, u8 stat) -{ - if (stat != 0x00) { - if (DBG_HDLC && DBG_SPAN(xhfc_span)) { - printk(KERN_INFO DRIVER_NAME "(port %d) STAT=0x%02x indicates " - "frame problem: %s\n", portno(xhfc_span), - stat, - (0xff == stat) ? "HDLC Abort" : "Bad FCS"); - } - - dahdi_hdlc_abort(xhfc_span->sigchan, (0xff == stat) ? - DAHDI_EVENT_ABORT : DAHDI_EVENT_BADFCS); - } else { - if (DBG_HDLC && DBG_SPAN(xhfc_span)) { - printk(KERN_INFO DRIVER_NAME - "(port %d) Frame " /*"%d" */ "is good!\n", - portno(xhfc_span) - /*, xhfc_span->frames_in */ ); - } - dahdi_hdlc_finish(xhfc_span->sigchan); - } -} - -/* - * Inner loop for D-channel receive function. Retrieves HDLC data from the - * hardware. If the hardware indicates that the frame is complete, we check - * the HDLC engine's STAT byte and update DAHDI as needed. - * - * Returns the number of HDLC frames left in the FIFO. */ -static int hdlc_rx_frame(struct xhfc_span *xhfc_span) -{ - char debugbuf[MAX(256, HDLC_BUF_LEN * 3 + 1)]; - int dbglen; - - int fifo, i, j, k, zleft; - int zlen, flen; - unsigned char buf[HDLC_BUF_LEN]; - struct xhfc *x = xhfc_span->xhfc; - - fifo = dchan_fifo(xhfc_span); - - if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): start\n", - __func__, fifo); - - xhfc_selfifo(x, fifo, RECEIVE); - - flen = get_Flen(x); - zlen = get_Zlen(x); - - debug_fz(fifo, __func__, debugbuf); - - if (!flen && !zlen) { - if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME - ": %s, nothing to receive (%ld)\n", - debugbuf, xhfc_span->non_rx_cnt); - xhfc_span->non_rx_cnt++; - return 0; - } - xhfc_span->non_rx_cnt = 0; - - if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); - - /* if we have at least one complete frame, increment zleft to include - * status byte */ - zleft = zlen; - if (flen) - zleft++; - - do { - j = zleft > HDLC_BUF_LEN ? HDLC_BUF_LEN : zleft; - - for (i = 0; i < j; i++) - buf[i] = read_xhfc(x, A_FIFO_DATA); - - /* don't send STAT byte to DAHDI */ - k = j; - if (xhfc_span->sigchan) { - if ((j != HDLC_BUF_LEN) && flen) - k--; - if (k) - dahdi_hdlc_putbuf(xhfc_span->sigchan, buf, k); - } - - zleft -= j; - - if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME - ": transmitted %d bytes to dahdi, " - "zleft=%d\n", k, zleft); - - if (DBG_HDLC && DBG_SPAN(xhfc_span)) { - dbglen = 0; - for (i = 0; i < j; i++) - dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); - debugbuf[dbglen] = '\0'; - - printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): " - "zlen=%d, zleft=%d: %s\n", __func__, - fifo, zlen, zleft, debugbuf); - } - } while (zleft > 0); - - /* Frame received, increment F2 */ - if (flen) - xhfc_inc_f(x); - - /* If this channel is not configured with a signalling span we don't - * need to notify the rest of dahdi about this frame. */ - if (!xhfc_span->sigchan) { - if (DBG_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME - ": %s(fifo %d): flen %d, early end\n", - __func__, fifo, flen); - return flen; - } - - if (flen) - hdlc_signal_complete(xhfc_span, buf[i - 1]); - - if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): flen=%d end\n", - __func__, fifo, flen); - - return flen; -} - -static uint frames_out; -/* -* Takes one blob of data from DAHDI and shoots it out to the hardware. The -* blob may or may not be a complete HDLC frame. If it isn't, the rest will be -* pulled during the next timer interrupt. -* Returns nonzero if there is still data to send in the current HDLC frame. -*/ -static int hdlc_tx_frame(struct xhfc_span *xhfc_span) -{ - struct xhfc *x = xhfc_span->xhfc; - struct dahdi_span *dahdi_span = &xhfc_span->span; - int res, i, fifo; - int zlen; - int flen = -1; - unsigned char buf[HDLC_BUF_LEN]; - unsigned int size = ARRAY_SIZE(buf); - char debugbuf[MAX(256, HDLC_BUF_LEN * 3 + 1)]; - int dbglen; - - /* ignoring TE red alarms: if TE and we are in alarm, restart the - * S/T state machine... */ - if (!xhfc_span->nt && (xhfc_span->span.alarms != 0)) { - activate_request(xhfc_span); - } - - fifo = dchan_fifo(xhfc_span); - res = dahdi_hdlc_getbuf(xhfc_span->sigchan, buf, &size); - - xhfc_selfifo(x, fifo, TRANSMIT); - - zlen = get_Zlen(x); - debug_fz(fifo, __func__, debugbuf); - - /* TODO: check zlen, etc. */ - if ((XHFC_ZMAX - zlen) < size) { - static int arg; - printk(KERN_INFO DRIVER_NAME ": arg (%d), zlen (%d) < what we " - "grabbed from DAHDI (%d)!\n", ++arg, zlen, size); - size = zlen; - dahdi_hdlc_abort(xhfc_span->sigchan, DAHDI_EVENT_OVERRUN); - } - - if (size > 0) { - - for (i = 0; i < size; i++) - write_xhfc(x, A_FIFO_DATA, buf[i]); - /* - * If we got a full frame from DAHDI, increment F and - * decrement our HDLC pending counter. */ - if (res != 0) { - frames_out++; - xhfc_inc_f(x); - atomic_dec(&xhfc_span->hdlc_pending); - } - } - - if (DBG_HDLC && DBG_SPAN(xhfc_span)) { - printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); - - dbglen = 0; - for (i = 0; i < size; i++) - dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); - debugbuf[dbglen] = '\0'; - - printk(KERN_INFO DRIVER_NAME - ": hdlc_tx_frame(span %d): DAHDI gave %d " - "bytes for FIFO %d (res = %d): %s\n", - dahdi_span->spanno, - size, fifo, res, debugbuf); - - if (size && res != 0) - printk(KERN_INFO DRIVER_NAME - ": Transmitted frame %d on span %d\n", - frames_out - 1, dahdi_span->spanno); - } - - return !res; -} - -/* DAHDI calls this when it has data it wants to send to the HDLC controller */ -void xhfc_hdlc_hard_xmit(struct dahdi_chan *chan) -{ - struct dahdi_span *dahdi_span = chan->span; - struct xhfc_span *xhfc_span = - container_of(dahdi_span, struct xhfc_span, span); - - if ((DBG_FOPS || DBG_HDLC) && DBG_SPAN(xhfc_span)) - printk(KERN_INFO DRIVER_NAME ": %s on chan %s (%i/%i), " - "span=%i (sigchan=%p, chan=%p): %d+1 frames\n", - __func__, chan->name, chan->channo, - chan->chanpos, dahdi_span->spanno, - xhfc_span->sigchan, chan, - atomic_read(&xhfc_span->hdlc_pending)); - - /* Increment the hdlc_pending counter and trigger hdlc_tx_frame */ - if (xhfc_span->sigchan == chan) - atomic_inc(&xhfc_span->hdlc_pending); -} - -/***************************************************************************** - * Interrupt handler, does all sort of stuff, some of which should prolly be * - * scheduled in a tasklet instead * - *****************************************************************************/ - -#define fifo_test(reg, fifonum, dir) (reg[fifonum/4] & (1 << (((fifonum % 4) * 2) + dir))) - -irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) -{ - - struct xhfc_pi *pi = dev_id; - struct xhfc *xhfc; - - int i; - u8 r_su_irq; - u8 misc_irq; - u8 fifo_irq[SPANS_PER_CHIP]; - u8 fifo_fill[SPANS_PER_CHIP]; - - (void) ptregs; - - xhfc = &pi->xhfc; - - /* IRQs for other HW with shared IRQ or spurious - * XXX for XiVO OpenHardware we should not share IRQ! */ - if (!(read_xhfc(xhfc, R_IRQ_OVIEW))) - return IRQ_NONE; - - /* reset IRQ source */ - misc_irq = read_xhfc(xhfc, R_MISC_IRQ); - - if (xhfc->running) { - /* check for Timer IRQ */ - if (misc_irq & M_TI_IRQMSK) - xhfc->ticks++; - - for(i = 0; i < SPANS_PER_CHIP; i++) { - fifo_irq[i] = read_xhfc(xhfc, R_FIFO_BL0_IRQ + i); - fifo_fill[i] = read_xhfc(xhfc, R_FILL_BL0 + i); - } - - for (i = 0; i < SPANS_PER_CHIP; i++) { - struct xhfc_span* s = &xhfc->spans[i]; - - if ((s->span.flags & DAHDI_FLAG_RUNNING) && s->sigchan && - s->span.alarms == DAHDI_ALARM_NONE) { - - /* No need to loop, makes no sense to receive - * more than one HDLC frame per second. - */ - if ( fifo_test(fifo_irq, dchan_fifo(s), RECEIVE) || - fifo_test(fifo_fill, dchan_fifo(s), RECEIVE)) - - hdlc_rx_frame(s); - - if (atomic_read(&s->hdlc_pending)) - hdlc_tx_frame(s); -#ifdef AUDIO - /* Put in readchunk chunk _previously_ retrieved - * from icp soft. - * We can't update it at icp level right now, - * because it has been written by trippy monkeys - * and it would probably be a very bad idea to - * try to call it from hardirq context. - * (look at ixOsalMutexLock ... :/ ) - */ - xivo_tdm_receive(pi->tdm_port, i*2 + 0, - s->chans[0]->readchunk); - xivo_tdm_receive(pi->tdm_port, i*2 + 1, - s->chans[1]->readchunk); - - dahdi_receive(&s->span); - dahdi_transmit(&s->span); - dahdi_ec_span(&s->span); - - xivo_tdm_transmit(pi->tdm_port, i*2 + 0, - s->chans[0]->writechunk); - xivo_tdm_transmit(pi->tdm_port, i*2 + 1, - s->chans[1]->writechunk); -#endif - } - } - -#ifdef AUDIO - xivo_tdm_tick(pi->tdm_port); -#endif - - r_su_irq = read_xhfc(xhfc, R_SU_IRQ); - - for (i = 0; i < SPANS_PER_CHIP; i++) { - handle_st_timers(&xhfc->spans[i]); - if (r_su_irq & (1 << i) || 2 == xhfc->ticks /* bootstrap XXX WTF*/) - handle_state_change(&xhfc->spans[i]); - } - } - - return IRQ_HANDLED; -} - - -/*****************************************************/ -/* disable all interrupts by disabling M_GLOB_IRQ_EN */ -/*****************************************************/ -static void disable_interrupts(struct xhfc * xhfc) -{ - printk(KERN_INFO "%s %s\n", xhfc->name, __func__); - - write_xhfc(xhfc, R_IRQ_CTRL, 0); - read_xhfc(xhfc, R_CHIP_ID); - mb(); - - set_mb(xhfc->running, 0); -} - - -/******************************************/ -/* start interrupt and set interrupt mask */ -/******************************************/ -static void enable_interrupts(struct xhfc * xhfc) -{ - u8 r_irq_ctrl = 0; - printk(KERN_INFO "%s %s\n", xhfc->name, __func__); - - set_mb(xhfc->running, 1); - - /* timer interrupt every 1 ms */ - write_xhfc(xhfc, R_TI_WD, 0x02); - write_xhfc(xhfc, R_MISC_IRQMSK, M_TI_IRQMSK); - - /* clear all pending interrupts bits */ - read_xhfc(xhfc, R_MISC_IRQ); - read_xhfc(xhfc, R_SU_IRQ); - read_xhfc(xhfc, R_FIFO_BL0_IRQ); - read_xhfc(xhfc, R_FIFO_BL1_IRQ); - read_xhfc(xhfc, R_FIFO_BL2_IRQ); - read_xhfc(xhfc, R_FIFO_BL3_IRQ); - - /* enable global interrupts */ - SET_V_GLOB_IRQ_EN(r_irq_ctrl, 1); - SET_V_FIFO_IRQ_EN(r_irq_ctrl, 1); - write_xhfc(xhfc, R_IRQ_CTRL, r_irq_ctrl); -} - - -/***********************************/ -/* initialise the XHFC ISDN Chip */ -/* return 0 on success. */ -/***********************************/ -int xhfc_collect_chip_id(struct xhfc * xhfc) -{ - u8 chip_id = read_xhfc(xhfc, R_CHIP_ID); - switch (chip_id) { - case CHIP_ID_1SU: - case CHIP_ID_2SU: - case CHIP_ID_2S4U: - case CHIP_ID_4SU: - printk(KERN_INFO "%s ChipID: 0x%x\n", - xhfc->name, chip_id); - return 0; - } - - printk(KERN_ERR "%s %s: unkown Chip ID 0x%x\n", - xhfc->name, __func__, chip_id); - return -EIO; -} - -void xhfc_hard_reset(void) -{ -#ifdef USE_GPIO - gpio_set_direction(reset_gpio, GPIO_OUTPUT); - gpio_set_to_gpio(reset_gpio); - gpio_set_level(reset_gpio, GPIO_LOW); - msleep(1); - gpio_set_level(reset_gpio, GPIO_HIGH); -#endif -} - -#if 0 -void configure_port(int port, int nt, int lineterm) -{ - gpio_set_direction(lineterm_gpio, GPIO_OUTPUT); - gpio_set_to_gpio(lineterm_gpio); - gpio_set_direction(ntte_gpio, GPIO_OUTPUT); - gpio_set_to_gpio(ntte_gpio); - gpio_set_level(lineterm_gpio, lineterm); - gpio_set_level(ntte_gpio, nt); -} -#endif - -void xhfc_init_and_configure(struct xhfc* x) -{ - u8 r_fifo_thres = 0; - /* In DAHDI's driver's this part is "stage 1" */ - xhfc_reset(x); - - /* Make sure interrupts disabled */ - disable_interrupts(x); - - /* "stage 2" */ - xhfc_config_pcm(x, XHFC_PCM_MASTER); - - /* Now we need to setup the flow controller and stuff */ - xhfc_config_data_flow(x); - - SET_V_THRES_RX(r_fifo_thres, 2); - SET_V_THRES_TX(r_fifo_thres, 2); - write_xhfc(x, R_FIFO_THRES, r_fifo_thres); -} - -static void xhfc_span_set_ntte(struct xhfc_span* s, int ntte) -{ - s->nt = !!ntte; - s->span.spantype = ntte ? "NT" : "TE"; -} - -int xhfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) -{ - struct xhfc_span *xhfc_span; - struct xhfc *xhfc; - int term; - - xhfc_span = container_of(span, struct xhfc_span, span); - xhfc = xhfc_span->xhfc; - - xhfc_span_set_ntte(xhfc_span, lc->lineconfig & DAHDI_CONFIG_NTTE); /* xref2 */ - - term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0; - - printk(KERN_INFO DRIVER_NAME ": Configuring port %d span %d in %s mode" - " with termination resistance %s\n", - portno(xhfc_span), span->spanno, - xhfc_span->nt ? "NT" : "TE", - term ? "ENABLED" : "DISABLED"); - - /* TODO conf hardware interface w/ GPIO */ - xhfc_config_st(xhfc, xhfc_span->port, xhfc_span->nt); - - printk(KERN_INFO DRIVER_NAME ": WARNING: This driver can't configure " - "the ports yet, expect problems if port %d isn't " - "configured in %s mode\n", - portno(xhfc_span), xhfc_span->nt ? "NT" : "TE"); - - if (lc->sync < 0) { - printk(KERN_INFO DRIVER_NAME - ": Span %d has invalid sync priority (%d), " - "removing from sync source list\n", - span->spanno, lc->sync); - lc->sync = 0; - } - - if (xhfc_span->nt && lc->sync) { - printk(KERN_INFO DRIVER_NAME - ": NT Spans cannot be timing sources. " - "Span %d requested to be timing source of " - "priority %d. Changing priority to 0\n", - span->offset, lc->sync); - lc->sync = 0; - } - - start_state_machine(xhfc_span); - - return 0; -} - -int xhfc_chanconfig(struct dahdi_chan *chan, int sigtype) -{ - int alreadyrunning; - struct xhfc_span *xhfc_span = container_of(chan->span, struct xhfc_span, span); - int res; - - alreadyrunning = xhfc_span->span.flags & DAHDI_FLAG_RUNNING; - - if (DBG_FOPS) - printk(KERN_INFO DRIVER_NAME - ": %s channel %d (%s) sigtype %08x\n", - alreadyrunning ? "Reconfigured" : "Configured", - chan->channo, chan->name, sigtype); - - switch (sigtype) { - case DAHDI_SIG_HARDHDLC: - /* xref1 */ - if (DBG_FOPS) - printk(KERN_INFO DRIVER_NAME - ": Configuring hardware HDLC on %s\n", - chan->name); - xhfc_span->sigchan = chan; - atomic_set(&xhfc_span->hdlc_pending, 0); - res = 0; - break; - case DAHDI_SIG_HDLCFCS: - printk(KERN_INFO DRIVER_NAME ": HDLCFCS not supported\n"); - res = -ENOSYS; - break; - case DAHDI_SIG_HDLCNET: - printk(KERN_INFO DRIVER_NAME ": HDLCNET not supported\n"); - res = -ENOSYS; - break; - case DAHDI_SIG_HDLCRAW: - printk(KERN_INFO DRIVER_NAME ": HDLCRAW not supported\n"); - res = -ENOSYS; - break; - default: - res = 0; - break; - }; - - return res; -} - -static int xhfc_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) -{ - return -ENOTTY; -} - -static int xhfc_span_startup(struct dahdi_span* s) -{ - struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); - activate_request(xhfc_span); - return 0; -} - -static int xhfc_span_shutdown(struct dahdi_span* s) -{ - struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); - deactivate_request(xhfc_span); - return 0; -} - -static const struct dahdi_span_ops xhfc_span_ops = { - .owner = THIS_MODULE, - .spanconfig = xhfc_spanconfig, - .chanconfig = xhfc_chanconfig, - .startup = xhfc_span_startup, - .shutdown = xhfc_span_shutdown, - .ioctl = xhfc_ioctl, - .hdlc_hard_xmit = xhfc_hdlc_hard_xmit, -}; - -/************************************************************************ - * Responsible for initializing the xhfc_span and dahdi_span structures * - ************************************************************************/ -void init_spans(struct xhfc* x) -{ - int i, j; - struct xhfc_span *xhfc_span; - struct dahdi_span *dahdi_span; - struct dahdi_chan *chan; - -/* for each span on the card */ - for (i = 0; i < SPANS_PER_CHIP; i++) { - - xhfc_span = &x->spans[i]; - dahdi_span = &xhfc_span->span; - - xhfc_span->xhfc = x; - xhfc_span->port = i; - - xhfc_span->sigchan = NULL; /* conf'd in chanconfig (xref1) */ - xhfc_span_set_ntte(xhfc_span, ntte & (1 << i)); /* reconf'd in spanconfig (xref2) */ - - /* All the timer stuff is done in the timer and state - * functions, not here. */ - - dahdi_span->ops = &xhfc_span_ops; - dahdi_span->chans = xhfc_span->chans; - dahdi_span->irq = x->pi->pci_dev->irq; - dahdi_span->offset = i; - dahdi_span->channels = CHANS_PER_SPAN; - dahdi_span->flags = 0; - dahdi_span->deflaw = DAHDI_LAW_ALAW; - dahdi_span->linecompat = - DAHDI_CONFIG_TERM | DAHDI_CONFIG_NTTE | - DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS ; - - sprintf(dahdi_span->name, "XHFC/%d", i+1); - sprintf(dahdi_span->desc, "XHFC port %d", i+1); - dahdi_span->manufacturer = "Avencall"; - dahdi_copy_string(dahdi_span->devicetype, "XHFC-4SU", - sizeof(dahdi_span->devicetype)); - sprintf(dahdi_span->location, "PCI Bus %02d Slot %02d", - x->pi->pci_dev->bus->number, - PCI_SLOT(x->pi->pci_dev->devfn) + 1); - - dahdi_span->alarms = DAHDI_ALARM_RED; - - - init_waitqueue_head(&dahdi_span->maintq); /* kinda everyone does this */ - - /* now initialize each channel in the span */ - for (j=0; j < CHANS_PER_SPAN; j++) { - xhfc_span->chans[j] = &xhfc_span->_chans[j]; - chan = xhfc_span->chans[j]; - chan->pvt = x; - - sprintf(chan->name, "XHFC/%d/%d", i + 1, j + 1); - - if (j == 2) { - chan->sigcap = DAHDI_SIG_HARDHDLC; - } else { - chan->sigcap = DAHDI_SIG_CLEAR | DAHDI_SIG_DACS; - } - chan->chanpos = j + 1; - chan->writechunk = (void *)(xhfc_span->writechunk + j * DAHDI_CHUNKSIZE); - chan->readchunk = (void *)(xhfc_span->readchunk + j * DAHDI_CHUNKSIZE); - } - } -} - -void release_card_irq(struct xhfc_pi * pi) -{ - disable_interrupts(&pi->xhfc); - free_irq(pi->irq, pi); -} - -static const struct pci_device_id tlp_leb_pci_tbl[] = { - { 0x8086, 0x503d, PCI_ANY_ID, PCI_ANY_ID, }, /* Intel Tolapai LEB controler */ - { } -}; -MODULE_DEVICE_TABLE(pci, tlp_leb_pci_tbl); - -static struct pci_driver xhfc_driver = { - .name = DRIVER_NAME, - .id_table = tlp_leb_pci_tbl, - .probe = xhfc_init_one, - .remove = __devexit_p(xhfc_remove_one), -// .shutdown = xhfc_shutdown, -}; - -/* pci.txt: called from process context */ -int __devinit xhfc_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int span; - struct xhfc_pi * pi; - unsigned long base, size; - int rc = -ENOMEM; - - printk(KERN_DEBUG "entering xhfc_init_one\n"); - - - /**************** - * Memory alloc * - ****************/ - - pi = kzalloc(sizeof(struct xhfc_pi), GFP_KERNEL); - if (pi == NULL) - goto err_alloc; - - sprintf(pi->name, "%s", DRIVER_NAME); /* ? */ - - printk(KERN_INFO "%s %s: adapter '%s' found on PCI bus %02x dev %02x\n", - pi->name, __func__, pi->name, - pdev->bus->number, pdev->devfn); - - - /************ - * PCI init * - ************/ - - rc = pci_enable_device(pdev); - - if (rc) - goto err_enable_device; - - printk(KERN_DEBUG "pci_enable_device succeeded\n"); - - rc = pci_request_regions(pdev, DRIVER_NAME); - if (rc) - goto err_request_regions; - - rc = -ENOMEM; - - base = pci_resource_start(pdev, LEB_CSRBAR); - size = pci_resource_len(pdev, LEB_CSRBAR); - pi->regs = ioremap(base, size); - if (!pi->regs) - goto err_ioremap_csrbar; - - base = pci_resource_start(pdev, LEB_MMBAR); - size = pci_resource_len(pdev, LEB_MMBAR); - pi->cs_n0 = ioremap(base, size); - if (!pi->cs_n0) - goto err_ioremap_mmbar; - - pci_set_drvdata(pdev, pi); - - - /************* - * Hard init * - *************/ - - xhfc_hard_reset(); - - if (exit_after_reset) { - rc = -EINVAL; - goto exit_after_reset; - } - - leb_init(pi); - - -#ifdef AUDIO - /************* - * TDM alloc * - *************/ - - pi->tdm_port = xivo_tdm_get_port(XIVO_XHFC_TDM_PORT); - if (!pi->tdm_port) { - rc = -EBUSY; - goto err_tdm_get_port; - } -#endif - - /******************** - * XHFC struct init * - ********************/ - - pi->pci_dev = pdev; - pi->xhfc.pi = pi; - - /* only adress one xhfc per PI */ - pi->xhfc.name = pi->name; - - /* init interrupt engine */ - rc = pi->irq = acpi_register_gsi( - IRQ_TLP_GPIO_24, - ACPI_LEVEL_SENSITIVE, - ACPI_ACTIVE_LOW); - if (rc < 0) - goto err_acpi_register; - - - /******** - * test * - ********/ - - rc = xhfc_collect_chip_id(&pi->xhfc); - if (rc) - goto err_collect_chip_id; - - - /*************** - * OK let's go * - ***************/ - - card_cnt++; - - if ((rc = request_irq(pi->irq, &xhfc_interrupt, 0, "XHFC", pi))) { - printk(KERN_WARNING "%s %s: couldn't get interrupt %d\n", - pi->name, __func__, pi->irq); - goto err_request_irq; - } - - init_spans(&pi->xhfc); - - xhfc_init_and_configure(&pi->xhfc); -#ifdef AUDIO - /* TDM started on the XHFC side, XHFC is MASTER */ - /* Now it's possible to start the TDM bus on the EP80579 side, as SLAVE: */ - if ((rc = xivo_tdm_config_port(pi->tdm_port, XHFC_MEGREZ_PROTO_XIVO_CONFIG)) < 0) { - printk(KERN_ERR "%s %s: xivo_tdm_config_port failed (err=%d)\n", pi->name, __func__, rc); - goto err_tdm_config_port; - } -#endif - - for (span = 0; span < SPANS_PER_CHIP; span++) - if ((rc = dahdi_register(&pi->xhfc.spans[span].span, /*prefmaster*/ 1)) < 0) { - printk(KERN_WARNING "%s %s: couldn't register spans\n", pi->name, __func__); - goto err_in_dahdi_register; - } - - enable_interrupts(&pi->xhfc); - -#ifdef AUDIO - xivo_tdm_start_chans(pi->tdm_port, - /* timeslots 0->7 */ 0xFF, - NULL); -#endif - - return 0; - -err_in_dahdi_register: - for (span--; span >= 0; span--) - dahdi_unregister(&pi->xhfc.spans[span].span); -#ifdef AUDIO -err_tdm_config_port: -#endif - free_irq(pi->irq, pi); -err_request_irq: -err_collect_chip_id: - //acpi_unregister_gsi(IRQ_TLP_GPIO_30); /* symbol doesn't exist??? */ -err_acpi_register: -#ifdef AUDIO - xivo_tdm_put_port(pi->tdm_port); -err_tdm_get_port: -#endif -exit_after_reset: - iounmap(pi->cs_n0); -err_ioremap_mmbar: - iounmap(pi->regs); -err_ioremap_csrbar: - pci_release_regions(pdev); -err_request_regions: - pci_disable_device(pdev); -err_enable_device: - kfree(pi); -err_alloc: - return rc; -} - -void __devexit xhfc_remove_one(struct pci_dev *pdev) -{ - int i; - struct xhfc_pi *pi; - - pi = pci_get_drvdata(pdev); - - if (DBG) - printk(KERN_INFO "%s %s: removing card\n", - pi->name, __func__); - - for (i = 0; i < SPANS_PER_CHIP; i++) - dahdi_unregister(&pi->xhfc.spans[i].span); - - release_card_irq(pi); - - card_cnt--; - - iounmap(pi->regs); - pi->regs = NULL; - iounmap(pi->cs_n0); - pi->cs_n0 = NULL; - - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - kfree(pi); - - printk(KERN_DEBUG "%s: bye-bye\n", __func__); -} - -/***************/ -/* Module init */ -/***************/ -static int __init xhfc_init(void) -{ - int err; - - if (DBG) - printk(KERN_INFO DRIVER_NAME " driver Rev. %s\n", xhfc_rev); - - err = dahdi_pci_module(&xhfc_driver); - if (err < 0) - goto out; - - /* XXX fail with error if no cards detected */ - - return 0; - - out: - return (err); -} - -static void __exit xhfc_cleanup(void) -{ - pci_unregister_driver(&xhfc_driver); - if (DBG) - printk(KERN_INFO "%s: driver removed\n", __func__); -} - -module_init(xhfc_init); -module_exit(xhfc_cleanup); - -- cgit v1.2.3