From 14198aee8532bbafed2ad1297177f8e0e0f13f50 Mon Sep 17 00:00:00 2001 From: Keith Morgan Date: Wed, 3 Oct 2018 14:04:04 +0000 Subject: [PATCH] Remove support for wcfxo driver. --- drivers/dahdi/Kbuild | 1 - drivers/dahdi/Kconfig | 10 - drivers/dahdi/wcfxo.c | 1105 ----------------------------------------- 3 files changed, 1116 deletions(-) delete mode 100644 drivers/dahdi/wcfxo.c diff --git a/drivers/dahdi/Kbuild b/drivers/dahdi/Kbuild index 83af341..4a0b24e 100644 --- a/drivers/dahdi/Kbuild +++ b/drivers/dahdi/Kbuild @@ -43,7 +43,6 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCB4XXP) += wcb4xxp/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT1XXP) += wct1xxp.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE11XP) += wcte11xp.o -obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCFXO) += wcfxo.o endif obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPP) += xpp/ diff --git a/drivers/dahdi/Kconfig b/drivers/dahdi/Kconfig index 0f10679..8e0f2f9 100644 --- a/drivers/dahdi/Kconfig +++ b/drivers/dahdi/Kconfig @@ -252,16 +252,6 @@ config DAHDI_DYNAMIC_LOC If unsure, say Y. -config DAHDI_WCFXO - tristate "Digium Wildcard X100P Support" - depends on DAHDI && PCI - default DAHDI - ---help--- - To compile this driver as a module, choose M here: the - module will be called wcfxo. - - If unsure, say Y. - config DAHDI_WCT1XXP tristate "Digium Wildcard T100P Support" depends on DAHDI && PCI diff --git a/drivers/dahdi/wcfxo.c b/drivers/dahdi/wcfxo.c deleted file mode 100644 index bf1d467..0000000 --- a/drivers/dahdi/wcfxo.c +++ /dev/null @@ -1,1105 +0,0 @@ -/* - * Wildcard X100P FXO Interface Driver for DAHDI Telephony interface - * - * Written by Mark Spencer - * Matthew Fredrickson - * - * Copyright (C) 2001-2008, Digium, Inc. - * - * All rights reserved. - * - */ - -/* - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2 as published by the - * Free Software Foundation. See the LICENSE file included with - * this program for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Uncomment to enable tasklet handling in the FXO driver. Not recommended - in general, but may improve interactive performance */ - -/* #define ENABLE_TASKLETS */ - -/* Un-comment the following for POTS line support for Japan */ -/* #define JAPAN */ - -/* Un-comment for lines (eg from and ISDN TA) that remove */ -/* phone power during ringing */ -/* #define ZERO_BATT_RING */ - -#define WC_MAX_IFACES 128 - -#define WC_CNTL 0x00 -#define WC_OPER 0x01 -#define WC_AUXC 0x02 -#define WC_AUXD 0x03 -#define WC_MASK0 0x04 -#define WC_MASK1 0x05 -#define WC_INTSTAT 0x06 - -#define WC_DMAWS 0x08 -#define WC_DMAWI 0x0c -#define WC_DMAWE 0x10 -#define WC_DMARS 0x18 -#define WC_DMARI 0x1c -#define WC_DMARE 0x20 - -#define WC_AUXFUNC 0x2b -#define WC_SERCTL 0x2d -#define WC_FSCDELAY 0x2f - - -/* DAA registers */ -#define WC_DAA_CTL1 1 -#define WC_DAA_CTL2 2 -#define WC_DAA_DCTL1 5 -#define WC_DAA_DCTL2 6 -#define WC_DAA_PLL1_N1 7 -#define WC_DAA_PLL1_M1 8 -#define WC_DAA_PLL2_N2_M2 9 -#define WC_DAA_PLL_CTL 10 -#define WC_DAA_CHIPA_REV 11 -#define WC_DAA_LINE_STAT 12 -#define WC_DAA_CHIPB_REV 13 -#define WC_DAA_DAISY_CTL 14 -#define WC_DAA_TXRX_GCTL 15 -#define WC_DAA_INT_CTL1 16 -#define WC_DAA_INT_CTL2 17 -#define WC_DAA_INT_CTL3 18 -#define WC_DAA_INT_CTL4 19 - - -#define FLAG_EMPTY 0 -#define FLAG_WRITE 1 -#define FLAG_READ 2 - -#ifdef ZERO_BATT_RING /* Need to debounce Off/On hook too */ -#define JAPAN -#endif - -#define RING_DEBOUNCE 64 /* Ringer Debounce (in ms) */ -#ifdef JAPAN -#define BATT_DEBOUNCE 30 /* Battery debounce (in ms) */ -#define OH_DEBOUNCE 350 /* Off/On hook debounce (in ms) */ -#else -#define BATT_DEBOUNCE 80 /* Battery debounce (in ms) */ -#endif - -#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ -#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ -#define PEGCOUNT 5 /* 5 cycles of pegging means RING */ - -#define wcfxo_printk(level, span, fmt, ...) \ - printk(KERN_ ## level "%s-%s: %s: " fmt, #level, \ - THIS_MODULE->name, (span).name, ## __VA_ARGS__) - -#define wcfxo_notice(span, fmt, ...) \ - wcfxo_printk(NOTICE, span, fmt, ## __VA_ARGS__) - -#define wcfxo_dbg(span, fmt, ...) \ - ((void)((debug) && wcfxo_printk(DEBUG, span, "%s: " fmt, \ - __FUNCTION__, ## __VA_ARGS__) ) ) - -struct reg { - unsigned long flags; - unsigned char index; - unsigned char reg; - unsigned char value; -}; - -static int wecareregs[] = -{ - WC_DAA_DCTL1, WC_DAA_DCTL2, WC_DAA_PLL2_N2_M2, WC_DAA_CHIPA_REV, - WC_DAA_LINE_STAT, WC_DAA_CHIPB_REV, WC_DAA_INT_CTL2, WC_DAA_INT_CTL4, -}; - -struct wcfxo { - struct pci_dev *dev; - char *variety; - struct dahdi_device *ddev; - struct dahdi_span span; - struct dahdi_chan _chan; - struct dahdi_chan *chan; - int usecount; - int dead; - int pos; - unsigned long flags; - int freeregion; - int ring; - int offhook; - int battery; - int wregcount; - int readpos; - int rreadpos; - unsigned int pegtimer; - int pegcount; - int peg; - int battdebounce; - int nobatttimer; - int ringdebounce; -#ifdef JAPAN - int ohdebounce; -#endif - int allread; - int regoffset; /* How far off our registers are from what we expect */ - int alt; - int ignoreread; - int reset; - /* Up to 6 register can be written at a time */ - struct reg regs[DAHDI_CHUNKSIZE]; - struct reg oldregs[DAHDI_CHUNKSIZE]; - unsigned char lasttx[DAHDI_CHUNKSIZE]; - /* Up to 32 registers of whatever we most recently read */ - unsigned char readregs[32]; - unsigned long ioaddr; - dma_addr_t readdma; - dma_addr_t writedma; - volatile int *writechunk; /* Double-word aligned write memory */ - volatile int *readchunk; /* Double-word aligned read memory */ -#ifdef ZERO_BATT_RING - int onhook; -#endif -#ifdef ENABLE_TASKLETS - int taskletrun; - int taskletsched; - int taskletpending; - int taskletexec; - int txerrors; - int ints; - struct tasklet_struct wcfxo_tlet; -#endif -}; - -#define FLAG_INVERTSER (1 << 0) -#define FLAG_USE_XTAL (1 << 1) -#define FLAG_DOUBLE_CLOCK (1 << 2) -#define FLAG_RESET_ON_AUX5 (1 << 3) -#define FLAG_NO_I18N_REGS (1 << 4) /*!< Uses si3035, rather si3034 */ - -struct wcfxo_desc { - char *name; - unsigned long flags; -}; - - -static struct wcfxo_desc wcx100p = { "Wildcard X100P", - FLAG_INVERTSER | FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; - -static struct wcfxo_desc wcx101p = { "Wildcard X101P", - FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; - -static struct wcfxo_desc generic = { "Generic Clone", - FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK }; - -static struct wcfxo *ifaces[WC_MAX_IFACES]; - -static void wcfxo_release(struct wcfxo *wc); - -static int debug = 0; - -static int monitor = 0; - -static int quiet = 0; - -static int boost = 0; - -static int opermode = 0; - -static struct fxo_mode { - char *name; - int ohs; - int act; - int dct; - int rz; - int rt; - int lim; - int vol; -} fxo_modes[] = -{ - { "FCC", 0, 0, 2, 0, 0, 0, 0 }, /* US */ - { "CTR21", 0, 0, 3, 0, 0, 3, 0 }, /* Austria, Belgium, Denmark, Finland, France, Germany, - Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands, - Norway, Portugal, Spain, Sweden, Switzerland, and UK */ -}; - -static inline void wcfxo_transmitprep(struct wcfxo *wc, unsigned char ints) -{ - volatile int *writechunk; - int x; - int written=0; - unsigned short cmd; - - /* if nothing to transmit, have to do the dahdi_transmit() anyway */ - if (!(ints & 3)) { - /* Calculate Transmission */ - dahdi_transmit(&wc->span); - return; - } - - /* Remember what it was we just sent */ - memcpy(wc->lasttx, wc->chan->writechunk, DAHDI_CHUNKSIZE); - - if (ints & 0x01) { - /* Write is at interrupt address. Start writing from normal offset */ - writechunk = wc->writechunk; - } else { - writechunk = wc->writechunk + DAHDI_CHUNKSIZE * 2; - } - - dahdi_transmit(&wc->span); - - for (x=0;xflags & FLAG_INVERTSER) - writechunk[x << 1] = cpu_to_le32( - ~((unsigned short)(DAHDI_XLAW(wc->chan->writechunk[x], wc->chan))| 0x1) << 16 - ); - else - writechunk[x << 1] = cpu_to_le32( - ((unsigned short)(DAHDI_XLAW(wc->chan->writechunk[x], wc->chan))| 0x1) << 16 - ); - - /* We always have a command to follow our signal */ - if (!wc->regs[x].flags) { - /* Fill in an empty register command with a read for a potentially useful register */ - wc->regs[x].flags = FLAG_READ; - wc->regs[x].reg = wecareregs[wc->readpos]; - wc->regs[x].index = wc->readpos; - wc->readpos++; - if (wc->readpos >= (sizeof(wecareregs) / sizeof(wecareregs[0]))) { - wc->allread = 1; - wc->readpos = 0; - } - } - - /* Prepare the command to follow it */ - switch(wc->regs[x].flags) { - case FLAG_READ: - cmd = (wc->regs[x].reg | 0x20) << 8; - break; - case FLAG_WRITE: - cmd = (wc->regs[x].reg << 8) | (wc->regs[x].value & 0xff); - written = 1; - /* Wait at least four samples before reading */ - wc->ignoreread = 4; - break; - default: - printk(KERN_DEBUG "wcfxo: Huh? No read or write??\n"); - cmd = 0; - } - /* Setup the write chunk */ - if (wc->flags & FLAG_INVERTSER) - writechunk[(x << 1) + 1] = cpu_to_le32(~(cmd << 16)); - else - writechunk[(x << 1) + 1] = cpu_to_le32(cmd << 16); - } - if (written) - wc->readpos = 0; - wc->wregcount = 0; - - for (x=0;xoldregs[x] = wc->regs[x]; - wc->regs[x].flags = FLAG_EMPTY; - } - -} - -static inline void wcfxo_receiveprep(struct wcfxo *wc, unsigned char ints) -{ - volatile int *readchunk; - int x; - int realreg; - int realval; - int sample; - if (ints & 0x04) - /* Read is at interrupt address. Valid data is available at normal offset */ - readchunk = wc->readchunk; - else - readchunk = wc->readchunk + DAHDI_CHUNKSIZE * 2; - - /* Keep track of how quickly our peg alternates */ - wc->pegtimer+=DAHDI_CHUNKSIZE; - for (x=0;xoldregs[x].flags == FLAG_READ && !wc->ignoreread) { - realreg = wecareregs[(wc->regs[x].index + wc->regoffset) % - (sizeof(wecareregs) / sizeof(wecareregs[0]))]; - realval = (le32_to_cpu(readchunk[(x << 1) +wc->alt]) >> 16) & 0xff; - if ((realval == 0x89) && (realreg != WC_DAA_PLL2_N2_M2)) { - /* Some sort of slippage, correct for it */ - while(realreg != WC_DAA_PLL2_N2_M2) { - /* Find register 9 */ - realreg = wecareregs[(wc->regs[x].index + ++wc->regoffset) % - (sizeof(wecareregs) / sizeof(wecareregs[0]))]; - wc->regoffset = wc->regoffset % (sizeof(wecareregs) / sizeof(wecareregs[0])); - } - if (debug) - printk(KERN_DEBUG "New regoffset: %d\n", wc->regoffset); - } - /* Receive into the proper register */ - wc->readregs[realreg] = realval; - } - /* Look for pegging to indicate ringing */ - sample = (short)(le32_to_cpu(readchunk[(x << 1) + (1 - wc->alt)]) >> 16); - if ((sample > 32000) && (wc->peg != 1)) { - if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME)) - wc->pegcount++; - wc->pegtimer = 0; - wc->peg = 1; - } else if ((sample < -32000) && (wc->peg != -1)) { - if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME)) - wc->pegcount++; - wc->pegtimer = 0; - wc->peg = -1; - } - wc->chan->readchunk[x] = DAHDI_LIN2X((sample), (wc->chan)); - } - if (wc->pegtimer > PEGTIME) { - /* Reset pegcount if our timer expires */ - wc->pegcount = 0; - } - /* Decrement debouncer if appropriate */ - if (wc->ringdebounce) - wc->ringdebounce--; - if (!wc->offhook && !wc->ringdebounce) { - if (!wc->ring && (wc->pegcount > PEGCOUNT)) { - /* It's ringing */ - if (debug) - printk(KERN_DEBUG "RING!\n"); - dahdi_hooksig(wc->chan, DAHDI_RXSIG_RING); - wc->ring = 1; - } - if (wc->ring && !wc->pegcount) { - /* No more ring */ - if (debug) - printk(KERN_DEBUG "NO RING!\n"); - dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); - wc->ring = 0; - } - } - if (wc->ignoreread) - wc->ignoreread--; - - /* Do the echo cancellation... We are echo cancelling against - what we sent two chunks ago*/ - dahdi_ec_chunk(wc->chan, wc->chan->readchunk, wc->lasttx); - - /* Receive the result */ - dahdi_receive(&wc->span); -} - -#ifdef ENABLE_TASKLETS -static void wcfxo_tasklet(unsigned long data) -{ - struct wcfxo *wc = (struct wcfxo *)data; - wc->taskletrun++; - /* Run tasklet */ - if (wc->taskletpending) { - wc->taskletexec++; - wcfxo_receiveprep(wc, wc->ints); - wcfxo_transmitprep(wc, wc->ints); - } - wc->taskletpending = 0; -} -#endif - -static void wcfxo_stop_dma(struct wcfxo *wc); -static void wcfxo_restart_dma(struct wcfxo *wc); - -DAHDI_IRQ_HANDLER(wcfxo_interrupt) -{ - struct wcfxo *wc = dev_id; - unsigned char ints; - unsigned char b; -#ifdef DEBUG_RING - static int oldb = 0; - static int oldcnt = 0; -#endif - - ints = inb(wc->ioaddr + WC_INTSTAT); - - - if (!ints) - return IRQ_NONE; - - outb(ints, wc->ioaddr + WC_INTSTAT); - - if (ints & 0x0c) { /* if there is a rx interrupt pending */ -#ifdef ENABLE_TASKLETS - wc->ints = ints; - if (!wc->taskletpending) { - wc->taskletpending = 1; - wc->taskletsched++; - tasklet_hi_schedule(&wc->wcfxo_tlet); - } else - wc->txerrors++; -#else - wcfxo_receiveprep(wc, ints); - /* transmitprep looks to see if there is anything to transmit - and returns by itself if there is nothing */ - wcfxo_transmitprep(wc, ints); -#endif - } - - if (ints & 0x10) { - printk(KERN_INFO "FXO PCI Master abort\n"); - /* Stop DMA andlet the watchdog start it again */ - wcfxo_stop_dma(wc); - return IRQ_RETVAL(1); - } - - if (ints & 0x20) { - printk(KERN_INFO "PCI Target abort\n"); - return IRQ_RETVAL(1); - } - if (1 /* !(wc->report % 0xf) */) { - /* Check for BATTERY from register and debounce for 8 ms */ - b = wc->readregs[WC_DAA_LINE_STAT] & 0xf; - if (!b) { - wc->nobatttimer++; -#if 0 - if (wc->battery) - printk(KERN_DEBUG "Battery loss: %d (%d debounce)\n", b, wc->battdebounce); -#endif - if (wc->battery && !wc->battdebounce) { - if (debug) - printk(KERN_DEBUG "NO BATTERY!\n"); - wc->battery = 0; -#ifdef JAPAN - if ((!wc->ohdebounce) && wc->offhook) { - dahdi_hooksig(wc->chan, DAHDI_RXSIG_ONHOOK); - if (debug) - printk(KERN_DEBUG "Signalled On Hook\n"); -#ifdef ZERO_BATT_RING - wc->onhook++; -#endif - } -#else - dahdi_hooksig(wc->chan, DAHDI_RXSIG_ONHOOK); -#endif - wc->battdebounce = BATT_DEBOUNCE; - } else if (!wc->battery) - wc->battdebounce = BATT_DEBOUNCE; - if ((wc->nobatttimer > 5000) && -#ifdef ZERO_BATT_RING - !(wc->readregs[WC_DAA_DCTL1] & 0x04) && -#endif - (!wc->span.alarms)) { - wc->span.alarms = DAHDI_ALARM_RED; - dahdi_alarm_notify(&wc->span); - } - } else if (b == 0xf) { - if (!wc->battery && !wc->battdebounce) { - if (debug) - printk(KERN_DEBUG "BATTERY!\n"); -#ifdef ZERO_BATT_RING - if (wc->onhook) { - wc->onhook = 0; - dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); - if (debug) - printk(KERN_DEBUG "Signalled Off Hook\n"); - } -#else - dahdi_hooksig(wc->chan, DAHDI_RXSIG_OFFHOOK); -#endif - wc->battery = 1; - wc->nobatttimer = 0; - wc->battdebounce = BATT_DEBOUNCE; - if (wc->span.alarms) { - wc->span.alarms = 0; - dahdi_alarm_notify(&wc->span); - } - } else if (wc->battery) - wc->battdebounce = BATT_DEBOUNCE; - } else { - /* It's something else... */ - wc->battdebounce = BATT_DEBOUNCE; - } - - if (wc->battdebounce) - wc->battdebounce--; -#ifdef JAPAN - if (wc->ohdebounce) - wc->ohdebounce--; -#endif - - } - - return IRQ_RETVAL(1); -} - -static int wcfxo_setreg(struct wcfxo *wc, unsigned char reg, unsigned char value) -{ - int x; - if (wc->wregcount < DAHDI_CHUNKSIZE) { - x = wc->wregcount; - wc->regs[x].reg = reg; - wc->regs[x].value = value; - wc->regs[x].flags = FLAG_WRITE; - wc->wregcount++; - return 0; - } - printk(KERN_NOTICE "wcfxo: Out of space to write register %02x with %02x\n", reg, value); - return -1; -} - -static inline struct wcfxo *wcfxo_from_span(struct dahdi_span *span) -{ - return container_of(span, struct wcfxo, span); -} - -static int _wcfxo_open(struct dahdi_chan *chan) -{ - struct wcfxo *wc = chan->pvt; - if (wc->dead) - return -ENODEV; - wc->usecount++; - return 0; -} - -static int wcfxo_open(struct dahdi_chan *chan) -{ - int res; - unsigned long flags; - spin_lock_irqsave(&chan->lock, flags); - res = _wcfxo_open(chan); - spin_unlock_irqrestore(&chan->lock, flags); - return res; -} - -static int wcfxo_watchdog(struct dahdi_span *span, int event) -{ - printk(KERN_INFO "FXO: Restarting DMA\n"); - wcfxo_restart_dma(wcfxo_from_span(span)); - return 0; -} - -static int wcfxo_close(struct dahdi_chan *chan) -{ - struct wcfxo *wc = chan->pvt; - wc->usecount--; - /* If we're dead, release us now */ - if (!wc->usecount && wc->dead) - wcfxo_release(wc); - return 0; -} - -static int wcfxo_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) -{ - struct wcfxo *wc = chan->pvt; - int reg=0; - switch(txsig) { - case DAHDI_TXSIG_START: - case DAHDI_TXSIG_OFFHOOK: - /* Take off hook and enable normal mode reception. This must - be done in two steps because of a hardware bug. */ - reg = wc->readregs[WC_DAA_DCTL1] & ~0x08; - wcfxo_setreg(wc, WC_DAA_DCTL1, reg); - - reg = reg | 0x1; - wcfxo_setreg(wc, WC_DAA_DCTL1, reg); - wc->offhook = 1; -#ifdef JAPAN - wc->battery = 1; - wc->battdebounce = BATT_DEBOUNCE; - wc->ohdebounce = OH_DEBOUNCE; -#endif - break; - case DAHDI_TXSIG_ONHOOK: - /* Put on hook and enable on hook line monitor */ - reg = wc->readregs[WC_DAA_DCTL1] & 0xfe; - wcfxo_setreg(wc, WC_DAA_DCTL1, reg); - - reg = reg | 0x08; - wcfxo_setreg(wc, WC_DAA_DCTL1, reg); - wc->offhook = 0; - /* Don't accept a ring for another 1000 ms */ - wc->ringdebounce = 1000; -#ifdef JAPAN - wc->ohdebounce = OH_DEBOUNCE; -#endif - break; - default: - printk(KERN_NOTICE "wcfxo: Can't set tx state to %d\n", txsig); - } - if (debug) - printk(KERN_DEBUG "Setting hook state to %d (%02x)\n", txsig, reg); - return 0; -} - -static const struct dahdi_span_ops wcfxo_span_ops = { - .owner = THIS_MODULE, - .hooksig = wcfxo_hooksig, - .open = wcfxo_open, - .close = wcfxo_close, - .watchdog = wcfxo_watchdog, -}; - -static int wcfxo_initialize(struct wcfxo *wc) -{ - wc->ddev = dahdi_create_device(); - - /* DAHDI stuff */ - sprintf(wc->span.name, "WCFXO/%d", wc->pos); - snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); - sprintf(wc->chan->name, "WCFXO/%d/%d", wc->pos, 0); - wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", - wc->dev->bus->number, - PCI_SLOT(wc->dev->devfn) + 1); - if (!wc->ddev->location) - return -ENOMEM; - - wc->ddev->manufacturer = "Digium"; - wc->ddev->devicetype = wc->variety; - wc->chan->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF; - wc->chan->chanpos = 1; - wc->span.chans = &wc->chan; - wc->span.channels = 1; - wc->span.flags = DAHDI_FLAG_RBS; - wc->span.deflaw = DAHDI_LAW_MULAW; -#ifdef ENABLE_TASKLETS - tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc); -#endif - - wc->chan->pvt = wc; - wc->span.ops = &wcfxo_span_ops; - wc->span.spantype = SPANTYPE_ANALOG_FXO; - list_add_tail(&wc->span.device_node, &wc->ddev->spans); - if (dahdi_register_device(wc->ddev, &wc->dev->dev)) { - printk(KERN_NOTICE "Unable to register span with DAHDI\n"); - return -1; - } - return 0; -} - -static int wcfxo_hardware_init(struct wcfxo *wc) -{ - /* Hardware stuff */ - /* Reset PCI Interface chip and registers */ - outb(0x0e, wc->ioaddr + WC_CNTL); - - /* Set all to outputs except AUX 4, which is an input */ - outb(0xef, wc->ioaddr + WC_AUXC); - - /* Reset the DAA (DAA uses AUX5 for reset) */ - outb(0x00, wc->ioaddr + WC_AUXD); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1 + HZ / 800); - - /* Set hook state to on hook & un-reset the DAA */ - if (wc->flags & FLAG_RESET_ON_AUX5) { - /* Set hook state to on hook for when we switch. - Make sure reset is high */ - outb(0x34, wc->ioaddr + WC_AUXD); - } else { - /* Set hook state to on hook for when we switch */ - outb(0x24, wc->ioaddr + WC_AUXD); - } - - /* Back to normal, with automatic DMA wrap around */ - outb(0x01, wc->ioaddr + WC_CNTL); - - /* Make sure serial port and DMA are out of reset */ - outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL); - - /* Configure serial port for MSB->LSB operation */ - if (wc->flags & FLAG_DOUBLE_CLOCK) - outb(0xc1, wc->ioaddr + WC_SERCTL); - else - outb(0xc0, wc->ioaddr + WC_SERCTL); - - if (wc->flags & FLAG_USE_XTAL) { - /* Use the crystal oscillator */ - outb(0x04, wc->ioaddr + WC_AUXFUNC); - } - - /* Delay FSC by 2 so it's properly aligned */ - outb(0x2, wc->ioaddr + WC_FSCDELAY); - - /* Setup DMA Addresses */ - outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ - outl(wc->writedma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ - outl(wc->writedma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMAWE); /* End */ - - outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ - outl(wc->readdma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ - outl(wc->readdma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMARE); /* End */ - - /* Clear interrupts */ - outb(0xff, wc->ioaddr + WC_INTSTAT); - return 0; -} - -static void wcfxo_enable_interrupts(struct wcfxo *wc) -{ - /* Enable interrupts (we care about all of them) */ - outb(0x3f, wc->ioaddr + WC_MASK0); - /* No external interrupts */ - outb(0x00, wc->ioaddr + WC_MASK1); -} - -static void wcfxo_start_dma(struct wcfxo *wc) -{ - /* Reset Master and TDM */ - outb(0x0f, wc->ioaddr + WC_CNTL); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - outb(0x01, wc->ioaddr + WC_CNTL); - outb(0x01, wc->ioaddr + WC_OPER); -} - -static void wcfxo_restart_dma(struct wcfxo *wc) -{ - /* Reset Master and TDM */ - outb(0x01, wc->ioaddr + WC_CNTL); - outb(0x01, wc->ioaddr + WC_OPER); -} - - -static void wcfxo_stop_dma(struct wcfxo *wc) -{ - outb(0x00, wc->ioaddr + WC_OPER); -} - -static void wcfxo_reset_tdm(struct wcfxo *wc) -{ - /* Reset TDM */ - outb(0x0f, wc->ioaddr + WC_CNTL); -} - -static void wcfxo_disable_interrupts(struct wcfxo *wc) -{ - outb(0x00, wc->ioaddr + WC_MASK0); - outb(0x00, wc->ioaddr + WC_MASK1); -} - -static void wcfxo_set_daa_mode(struct wcfxo *wc) -{ - /* Set country specific parameters (OHS, ACT, DCT, RZ, RT, LIM, VOL) */ - int reg16 = ((fxo_modes[opermode].ohs & 0x1) << 6) | - ((fxo_modes[opermode].act & 0x1) << 5) | - ((fxo_modes[opermode].dct & 0x3) << 2) | - ((fxo_modes[opermode].rz & 0x1) << 1) | - ((fxo_modes[opermode].rt & 0x1) << 0); - int reg17 = ((fxo_modes[opermode].lim & 0x3) << 3); - int reg18 = ((fxo_modes[opermode].vol & 0x3) << 3); - - if (wc->flags & FLAG_NO_I18N_REGS) { - wcfxo_dbg(wc->span, "This card does not support international settings.\n"); - return; - } - - wcfxo_setreg(wc, WC_DAA_INT_CTL1, reg16); - wcfxo_setreg(wc, WC_DAA_INT_CTL2, reg17); - wcfxo_setreg(wc, WC_DAA_INT_CTL3, reg18); - - - /* Wait a couple of jiffies for our writes to finish */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); - - printk(KERN_INFO "wcfxo: DAA mode is '%s'\n", fxo_modes[opermode].name); -} - -static int wcfxo_init_daa(struct wcfxo *wc) -{ - /* This must not be called in an interrupt */ - /* We let things settle for a bit */ - unsigned char reg15; - int chip_revb; -// set_current_state(TASK_INTERRUPTIBLE); -// schedule_timeout(10); - - /* Soft-reset it */ - wcfxo_setreg(wc, WC_DAA_CTL1, 0x80); - - /* Let the reset go */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); - - /* We have a clock at 18.432 Mhz, so N1=1, M1=2, CGM=0 */ - wcfxo_setreg(wc, WC_DAA_PLL1_N1, 0x0); /* This value is N1 - 1 */ - wcfxo_setreg(wc, WC_DAA_PLL1_M1, 0x1); /* This value is M1 - 1 */ - /* We want to sample at 8khz, so N2 = 9, M2 = 10 (N2-1, M2-1) */ - wcfxo_setreg(wc, WC_DAA_PLL2_N2_M2, 0x89); - - /* Wait until the PLL's are locked. Time is between 100 uSec and 1 mSec */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1 + HZ/1000 + (DAHDI_CHUNKSIZE * HZ) / 800); - - /* No additional ration is applied to the PLL and faster lock times - * are possible */ - wcfxo_setreg(wc, WC_DAA_PLL_CTL, 0x0); - /* Enable off hook pin */ - wcfxo_setreg(wc, WC_DAA_DCTL1, 0x0a); - if (monitor) { - /* Enable ISOcap and external speaker and charge pump if present */ - wcfxo_setreg(wc, WC_DAA_DCTL2, 0x80); - } else { - /* Enable ISOcap and charge pump if present (leave speaker disabled) */ - wcfxo_setreg(wc, WC_DAA_DCTL2, 0xe0); - } - - /* Wait a couple of jiffies for our writes to finish */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1 + (DAHDI_CHUNKSIZE * HZ) / 800); - reg15 = 0x0; - /* Go ahead and attenuate transmit signal by 6 db */ - if (quiet) { - printk(KERN_INFO "wcfxo: Attenuating transmit signal for quiet operation\n"); - reg15 |= (quiet & 0x3) << 4; - } - if (boost) { - printk(KERN_INFO "wcfxo: Boosting receive signal\n"); - reg15 |= (boost & 0x3); - } - wcfxo_setreg(wc, WC_DAA_TXRX_GCTL, reg15); - - /* REVB: reg. 13, bits 5:2 */ - chip_revb = (wc->readregs[WC_DAA_CHIPB_REV] >> 2) & 0xF; - wcfxo_dbg(wc->span, "DAA chip REVB is %x\n", chip_revb); - switch(chip_revb) { - case 1: case 2: case 3: - /* This is a si3034. Nothing to do */ - break; - case 4: case 5: case 7: - /* This is 3035. Has no support for international registers */ - wc->flags |= FLAG_NO_I18N_REGS; - break; - default: - wcfxo_notice(wc->span, "Unknown DAA chip revision: REVB=%d\n", - chip_revb); - } - - /* Didn't get it right. Register 9 is still garbage */ - if (wc->readregs[WC_DAA_PLL2_N2_M2] != 0x89) - return -1; -#if 0 - { int x; - int y; - for (y=0;y<100;y++) { - printk(KERN_DEBUG " reg dump ====== %d ======\n", y); - for (x=0;xreadregs[wecareregs[x]]); - } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100); - } } -#endif - return 0; -} - -static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct wcfxo *wc; - struct wcfxo_desc *d = (struct wcfxo_desc *)ent->driver_data; - int x; - - for (x=0;x= WC_MAX_IFACES) { - printk(KERN_ERR "Too many interfaces: Found %d, can only handle %d.\n", - x, WC_MAX_IFACES - 1); - return -EIO; - } - - if (pci_enable_device(pdev)) - return -EIO; - - wc = kmalloc(sizeof(struct wcfxo), GFP_KERNEL); - if (!wc) { - printk(KERN_ERR "wcfxo: Failed initializinf card. Not enough memory."); - return -ENOMEM; - } - - ifaces[x] = wc; - memset(wc, 0, sizeof(struct wcfxo)); - wc->chan = &wc->_chan; - wc->ioaddr = pci_resource_start(pdev, 0); - wc->dev = pdev; - wc->pos = x; - wc->variety = d->name; - wc->flags = d->flags; - /* Keep track of whether we need to free the region */ - if (request_region(wc->ioaddr, 0xff, "wcfxo")) - wc->freeregion = 1; - - /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses - 32 bits. Allocate an extra set just for control too */ - wc->writechunk = (int *)pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma); - if (!wc->writechunk) { - printk(KERN_NOTICE "wcfxo: Unable to allocate DMA-able memory\n"); - if (wc->freeregion) - release_region(wc->ioaddr, 0xff); - return -ENOMEM; - } - - wc->readchunk = wc->writechunk + DAHDI_MAX_CHUNKSIZE * 4; /* in doublewords */ - wc->readdma = wc->writedma + DAHDI_MAX_CHUNKSIZE * 16; /* in bytes */ - - if (wcfxo_initialize(wc)) { - printk(KERN_NOTICE "wcfxo: Unable to intialize modem\n"); - if (wc->freeregion) - release_region(wc->ioaddr, 0xff); - kfree(wc); - return -EIO; - } - - /* Enable bus mastering */ - pci_set_master(pdev); - - /* Keep track of which device we are */ - pci_set_drvdata(pdev, wc); - - if (request_irq(pdev->irq, wcfxo_interrupt, IRQF_SHARED, "wcfxo", wc)) { - printk(KERN_NOTICE "wcfxo: Unable to request IRQ %d\n", pdev->irq); - if (wc->freeregion) - release_region(wc->ioaddr, 0xff); - kfree(wc); - return -EIO; - } - - - wcfxo_hardware_init(wc); - /* Enable interrupts */ - wcfxo_enable_interrupts(wc); - /* Initialize Write/Buffers to all blank data */ - memset((void *)wc->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4); - /* Start DMA */ - wcfxo_start_dma(wc); - - /* Initialize DAA (after it's started) */ - if (wcfxo_init_daa(wc)) { - printk(KERN_NOTICE "Failed to initailize DAA, giving up...\n"); - wcfxo_stop_dma(wc); - wcfxo_disable_interrupts(wc); - dahdi_unregister_device(wc->ddev); - free_irq(pdev->irq, wc); - - /* Reset PCI chip and registers */ - outb(0x0e, wc->ioaddr + WC_CNTL); - - if (wc->freeregion) - release_region(wc->ioaddr, 0xff); - kfree(wc->ddev->location); - dahdi_free_device(wc->ddev); - kfree(wc); - return -EIO; - } - wcfxo_set_daa_mode(wc); - printk(KERN_INFO "Found a Wildcard FXO: %s\n", wc->variety); - - return 0; -} - -static void wcfxo_release(struct wcfxo *wc) -{ - dahdi_unregister_device(wc->ddev); - if (wc->freeregion) - release_region(wc->ioaddr, 0xff); - kfree(wc->ddev->location); - dahdi_free_device(wc->ddev); - kfree(wc); - printk(KERN_INFO "Freed a Wildcard\n"); -} - -static void __devexit wcfxo_remove_one(struct pci_dev *pdev) -{ - struct wcfxo *wc = pci_get_drvdata(pdev); - if (wc) { - - /* Stop any DMA */ - wcfxo_stop_dma(wc); - wcfxo_reset_tdm(wc); - - /* In case hardware is still there */ - wcfxo_disable_interrupts(wc); - - /* Immediately free resources */ - pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); - free_irq(pdev->irq, wc); - - /* Reset PCI chip and registers */ - outb(0x0e, wc->ioaddr + WC_CNTL); - - /* Release span, possibly delayed */ - if (!wc->usecount) - wcfxo_release(wc); - else - wc->dead = 1; - } -} - -static DEFINE_PCI_DEVICE_TABLE(wcfxo_pci_tbl) = { - { 0xe159, 0x0001, 0x8084, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, - { 0xe159, 0x0001, 0x8085, PCI_ANY_ID, 0, 0, (unsigned long) &wcx101p }, - { 0xe159, 0x0001, 0x8086, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, - { 0xe159, 0x0001, 0x8087, PCI_ANY_ID, 0, 0, (unsigned long) &generic }, - { 0x1057, 0x5608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcx100p }, - { 0 } -}; - -MODULE_DEVICE_TABLE (pci, wcfxo_pci_tbl); - -static struct pci_driver wcfxo_driver = { - .name = "wcfxo", - .probe = wcfxo_init_one, - .remove = __devexit_p(wcfxo_remove_one), - .id_table = wcfxo_pci_tbl, -}; - -static int __init wcfxo_init(void) -{ - int res; - int x; - if ((opermode >= sizeof(fxo_modes) / sizeof(fxo_modes[0])) || (opermode < 0)) { - printk(KERN_NOTICE "Invalid/unknown operating mode specified. Please choose one of:\n"); - for (x=0;x"); -MODULE_LICENSE("GPL v2"); - -module_init(wcfxo_init); -module_exit(wcfxo_cleanup);