/* * * hfcpci.c low level driver for CCD's hfc-pci based cards * * Author Werner Cornelius (werner@isdn4linux.de) * based on existing driver for CCD hfc ISA cards * type approval valid for HFC-S PCI A based card * * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) * Copyright 2008 by Karsten Keil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Module options: * * debug: * NOTE: only one poll value must be given for all cards * See hfc_pci.h for debug flags. * * poll: * NOTE: only one poll value must be given for all cards * Give the number of samples for each fifo process. * By default 128 is used. Decrease to reduce delay, increase to * reduce cpu load. If unsure, don't mess with it! * A value of 128 will use controller's interrupt. Other values will * use kernel timer, because the controller will not allow lower values * than 128. * Also note that the value depends on the kernel timer frequency. * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. * If the kernel uses 100 Hz, steps of 80 samples are possible. * If the kernel uses 300 Hz, steps of about 26 samples are possible. * */ #include #include #include #include #include #include #include "hfc_pci.h" static const char *hfcpci_revision = "2.0"; static int HFC_cnt; static uint debug; static uint poll, tics; static struct timer_list hfc_tl; static unsigned long hfc_jiffies; MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); module_param(poll, uint, S_IRUGO | S_IWUSR); enum { HFC_CCD_2BD0, HFC_CCD_B000, HFC_CCD_B006, HFC_CCD_B007, HFC_CCD_B008, HFC_CCD_B009, HFC_CCD_B00A, HFC_CCD_B00B, HFC_CCD_B00C, HFC_CCD_B100, HFC_CCD_B700, HFC_CCD_B701, HFC_ASUS_0675, HFC_BERKOM_A1T, HFC_BERKOM_TCONCEPT, HFC_ANIGMA_MC145575, HFC_ZOLTRIX_2BD0, HFC_DIGI_DF_M_IOM2_E, HFC_DIGI_DF_M_E, HFC_DIGI_DF_M_IOM2_A, HFC_DIGI_DF_M_A, HFC_ABOCOM_2BD1, HFC_SITECOM_DC105V2, }; struct hfcPCI_hw { unsigned char cirm; unsigned char ctmt; unsigned char clkdel; unsigned char states; unsigned char conn; unsigned char mst_m; unsigned char int_m1; unsigned char int_m2; unsigned char sctrl; unsigned char sctrl_r; unsigned char sctrl_e; unsigned char trm; unsigned char fifo_en; unsigned char bswapped; unsigned char protocol; int nt_timer; unsigned char __iomem *pci_io; /* start of PCI IO memory */ dma_addr_t dmahandle; void *fifos; /* FIFO memory */ int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; }; #define HFC_CFG_MASTER 1 #define HFC_CFG_SLAVE 2 #define HFC_CFG_PCM 3 #define HFC_CFG_2HFC 4 #define HFC_CFG_SLAVEHFC 5 #define HFC_CFG_NEG_F0 6 #define HFC_CFG_SW_DD_DU 7 #define FLG_HFC_TIMER_T1 16 #define FLG_HFC_TIMER_T3 17 #define NT_T1_COUNT 1120 /* number of 3.125ms interrupts (3.5s) */ #define NT_T3_COUNT 31 /* number of 3.125ms interrupts (97 ms) */ #define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ #define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ struct hfc_pci { u_char subtype; u_char chanlimit; u_char initdone; u_long cfg; u_int irq; u_int irqcnt; struct pci_dev *pdev; struct hfcPCI_hw hw; spinlock_t lock; /* card lock */ struct dchannel dch; struct bchannel bch[2]; }; /* Interface functions */ static void enable_hwirq(struct hfc_pci *hc) { hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); } static void disable_hwirq(struct hfc_pci *hc) { hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); } /* * free hardware resources used by driver */ static void release_io_hfcpci(struct hfc_pci *hc) { /* disable memory mapped ports + busmaster */ pci_write_config_word(hc->pdev, PCI_COMMAND, 0); del_timer(&hc->hw.timer); pci_free_consistent(hc->pdev, 0x8000, hc->hw.fifos, hc->hw.dmahandle); iounmap(hc->hw.pci_io); } /* * set mode (NT or TE) */ static void hfcpci_setmode(struct hfc_pci *hc) { if (hc->hw.protocol == ISDN_P_NT_S0) { hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */ hc->hw.states = 1; /* G1 */ } else { hc->hw.clkdel = CLKDEL_TE; /* ST-Bit delay for TE-Mode */ hc->hw.sctrl &= ~SCTRL_MODE_NT; /* TE-MODE */ hc->hw.states = 2; /* F2 */ } Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states); udelay(10); Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */ Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); } /* * function called to reset the HFC PCI chip. A complete software reset of chip * and fifos is done. */ static void reset_hfcpci(struct hfc_pci *hc) { u_char val; int cnt = 0; printk(KERN_DEBUG "reset_hfcpci: entered\n"); val = Read_hfc(hc, HFCPCI_CHIP_ID); printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); /* enable memory mapped ports, disable busmaster */ pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); disable_hwirq(hc); /* enable memory ports + busmaster */ pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); val = Read_hfc(hc, HFCPCI_STATUS); printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); hc->hw.cirm = HFCPCI_RESET; /* Reset On */ Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); set_current_state(TASK_UNINTERRUPTIBLE); mdelay(10); /* Timeout 10ms */ hc->hw.cirm = 0; /* Reset Off */ Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); val = Read_hfc(hc, HFCPCI_STATUS); printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val); while (cnt < 50000) { /* max 50000 us */ udelay(5); cnt += 5; val = Read_hfc(hc, HFCPCI_STATUS); if (!(val & 2)) break; } printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt); hc->hw.fifo_en = 0x30; /* only D fifos enabled */ hc->hw.bswapped = 0; /* no exchange */ hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ hc->hw.sctrl_r = 0; hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */ hc->hw.mst_m = 0; if (test_bit(HFC_CFG_MASTER, &hc->cfg)) hc->hw.mst_m |= HFCPCI_MASTER; /* HFC Master Mode */ if (test_bit(HFC_CFG_NEG_F0, &hc->cfg)) hc->hw.mst_m |= HFCPCI_F0_NEGATIV; Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* Clear already pending ints */ val = Read_hfc(hc, HFCPCI_INT_S1); /* set NT/TE mode */ hfcpci_setmode(hc); Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); /* * Init GCI/IOM2 in master mode * Slots 0 and 1 are set for B-chan 1 and 2 * D- and monitor/CI channel are not enabled * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC * STIO2 is used as data input, B1+B2 from IOM->ST * ST B-channel send disabled -> continuous 1s * The IOM slots are always enabled */ if (test_bit(HFC_CFG_PCM, &hc->cfg)) { /* set data flow directions: connect B1,B2: HFC to/from PCM */ hc->hw.conn = 0x09; } else { hc->hw.conn = 0x36; /* set data flow directions */ if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { Write_hfc(hc, HFCPCI_B1_SSL, 0xC0); Write_hfc(hc, HFCPCI_B2_SSL, 0xC1); Write_hfc(hc, HFCPCI_B1_RSL, 0xC0); Write_hfc(hc, HFCPCI_B2_RSL, 0xC1); } else { Write_hfc(hc, HFCPCI_B1_SSL, 0x80); Write_hfc(hc, HFCPCI_B2_SSL, 0x81); Write_hfc(hc, HFCPCI_B1_RSL, 0x80); Write_hfc(hc, HFCPCI_B2_RSL, 0x81); } } Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); val = Read_hfc(hc, HFCPCI_INT_S2); } /* * Timer function called when kernel timer expires */ static void hfcpci_Timer(struct hfc_pci *hc) {
/* $Id: capimain.c,v 1.24 2003/09/09 06:51:05 schindler Exp $
 *
 * ISDN interface module for Eicon active cards DIVA.
 * CAPI Interface
 *
 * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>

#include "os_capi.h"

#include "platform.h"
#include "di_defs.h"
#include "capi20.h"
#include "divacapi.h"
#include "cp_vers.h"
#include "capifunc.h"

static char *main_revision = "$Revision: 1.24 $";
static char *DRIVERNAME =
	"Eicon DIVA - CAPI Interface driver (http://www.melware.net)";
static char *DRIVERLNAME = "divacapi";

MODULE_DESCRIPTION("CAPI driver for Eicon DIVA cards");
MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
MODULE_SUPPORTED_DEVICE("CAPI and DIVA card drivers");
MODULE_LICENSE("GPL");

/*
 * get revision number from revision string
 */
static char *getrev(const char *revision)
{
	char *rev;
	char *p;
	if ((p = strchr(revision, ':'))) {
		rev = p + 2;
		p = strchr(rev, '$');
		*--p = 0;
	} else
		rev = "1.0";
	return rev;

}

/*
 * alloc a message buffer
 */
diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size,
						       void **data_buf)
{
	diva_os_message_buffer_s *dmb = alloc_skb(size, GFP_ATOMIC);
	if (dmb) {
		*data_buf = skb_put(dmb, size);
	}
	return (dmb);
}

/*
 * free a message buffer
 */
void diva_os_free_message_buffer(diva_os_message_buffer_s *dmb)
{
	kfree_skb(dmb);
}

/*
 * proc function for controller info
 */
static int diva_ctl_proc_show(struct seq_file *m, void *v)
{
	struct capi_ctr *ctrl = m->private;
	diva_card *card = (diva_card *) ctrl->driverdata;

	seq_printf(m, "%s\n", ctrl->name);
	seq_printf(m, "Serial No. : %s\n", ctrl->serial);
	seq_printf(m, "Id         : %d\n", card->Id);
	seq_printf(m, "Channels   : %d\n", card->d.channels);

	return 0;
}

static int diva_ctl_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, diva_ctl_proc_show, NULL);
}

static const struct file_operations diva_ctl_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= diva_ctl_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

/*
 * set additional os settings in capi_ctr struct
 */
void diva_os_set_controller_struct(struct capi_ctr *ctrl)
{
	ctrl->driver_name = DRIVERLNAME;
	ctrl->load_firmware = NULL;
	ctrl->reset_ctr = NULL;
	ctrl->proc_fops = &diva_ctl_proc_fops;
	ctrl->owner = THIS_MODULE;
}

/*
 * module init
 */
static int __init divacapi_init(void)
{
	char tmprev[32];
	int ret = 0;

	sprintf(DRIVERRELEASE_CAPI, "%d.%d%s", DRRELMAJOR, DRRELMINOR,
		DRRELEXTRA);

	printk(KERN_INFO "%s\n", DRIVERNAME);
	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_CAPI);
	strcpy(tmprev, main_revision);
	printk("%s  Build: %s(%s)\n", getrev(tmprev),
	       diva_capi_common_code_build, DIVA_BUILD);

	if (!(init_capifunc())) {
		printk(KERN_ERR "%s: failed init capi_driver.\n",
		       DRIVERLNAME);
		ret = -EIO;
	}

	return ret;
}

/*
 * module exit
 */
static void __exit divacapi_exit(void)
{
	finit_capifunc();
	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
}

module_init(divacapi_init);
module_exit(divacapi_exit);
d mode */ static int mode_hfcpci(struct bchannel *bch, int bc, int protocol) { struct hfc_pci *hc = bch->hw; int fifo2; u_char rx_slot = 0, tx_slot = 0, pcm_mode; if (bch->debug & DEBUG_HW_BCHANNEL) printk(KERN_DEBUG "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n", bch->state, protocol, bch->nr, bc); fifo2 = bc; pcm_mode = (bc >> 24) & 0xff; if (pcm_mode) { /* PCM SLOT USE */ if (!test_bit(HFC_CFG_PCM, &hc->cfg)) printk(KERN_WARNING "%s: pcm channel id without HFC_CFG_PCM\n", __func__); rx_slot = (bc >> 8) & 0xff; tx_slot = (bc >> 16) & 0xff; bc = bc & 0xff; } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE)) printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n", __func__); if (hc->chanlimit > 1) { hc->hw.bswapped = 0; /* B1 and B2 normal mode */ hc->hw.sctrl_e &= ~0x80; } else { if (bc & 2) { if (protocol != ISDN_P_NONE) { hc->hw.bswapped = 1; /* B1 and B2 exchanged */ hc->hw.sctrl_e |= 0x80; } else { hc->hw.bswapped = 0; /* B1 and B2 normal mode */ hc->hw.sctrl_e &= ~0x80; } fifo2 = 1; } else { hc->hw.bswapped = 0; /* B1 and B2 normal mode */ hc->hw.sctrl_e &= ~0x80; } } switch (protocol) { case (-1): /* used for init */ bch->state = -1; bch->nr = bc; case (ISDN_P_NONE): if (bch->state == ISDN_P_NONE) return 0; if (bc & 2) { hc->hw.sctrl &= ~SCTRL_B2_ENA; hc->hw.sctrl_r &= ~SCTRL_B2_ENA; } else { hc->hw.sctrl &= ~SCTRL_B1_ENA; hc->hw.sctrl_r &= ~SCTRL_B1_ENA; } if (fifo2 & 2) { hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS | HFCPCI_INTS_B2REC); } else { hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS | HFCPCI_INTS_B1REC); } #ifdef REVERSE_BITORDER if (bch->nr & 2) hc->hw.cirm &= 0x7f; else hc->hw.cirm &= 0xbf; #endif bch->state = ISDN_P_NONE; bch->nr = bc; test_and_clear_bit(FLG_HDLC, &bch->Flags); test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); break; case (ISDN_P_B_RAW): bch->state = protocol; bch->nr = bc; hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; #ifdef REVERSE_BITORDER hc->hw.cirm |= 0x80; #endif } else { hc->hw.sctrl |= SCTRL_B1_ENA; hc->hw.sctrl_r |= SCTRL_B1_ENA; #ifdef REVERSE_BITORDER hc->hw.cirm |= 0x40; #endif } if (fifo2 & 2) { hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; if (!tics) hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | HFCPCI_INTS_B2REC); hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; } else { hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; if (!tics) hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | HFCPCI_INTS_B1REC); hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; } test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); break; case (ISDN_P_B_HDLC): bch->state = protocol; bch->nr = bc; hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0); hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0); if (bc & 2) { hc->hw.sctrl |= SCTRL_B2_ENA; hc->hw.sctrl_r |= SCTRL_B2_ENA; } else { hc->hw.sctrl |= SCTRL_B1_ENA; hc->hw.sctrl_r |= SCTRL_B1_ENA; } if (fifo2 & 2) { hc->hw.last_bfifo_cnt[1] = 0; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS | HFCPCI_INTS_B2REC); hc->hw.ctmt &= ~2; hc->hw.conn &= ~0x18; } else { hc->hw.last_bfifo_cnt[0] = 0; hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS | HFCPCI_INTS_B1REC); hc->hw.ctmt &= ~1; hc->hw.conn &= ~0x03; } test_and_set_bit(FLG_HDLC, &bch->Flags); break; default: printk(KERN_DEBUG "prot not known %x\n", protocol); return -ENOPROTOOPT; } if (test_bit(HFC_CFG_PCM, &hc->cfg)) { if ((protocol == ISDN_P_NONE) || (protocol == -1)) { /* init case */ rx_slot = 0; tx_slot = 0; } else { if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) { rx_slot |= 0xC0; tx_slot |= 0xC0; } else { rx_slot |= 0x80; tx_slot |= 0x80; } } if (bc & 2) { hc->hw.conn &= 0xc7; hc->hw.conn |= 0x08; printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n", __func__, tx_slot); printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n", __func__, rx_slot); Write_hfc(hc, HFCPCI_B2_SSL, tx_slot); Write_hfc(hc, HFCPCI_B2_RSL, rx_slot); } else { hc->hw.conn &= 0xf8; hc->hw.conn |= 0x01; printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n", __func__, tx_slot); printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n", __func__, rx_slot); Write_hfc(hc, HFCPCI_B1_SSL, tx_slot); Write_hfc(hc, HFCPCI_B1_RSL, rx_slot); } } Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e); Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); #ifdef REVERSE_BITORDER Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); #endif return 0; } static int set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) { struct hfc_pci *hc = bch->hw; if (bch->debug & DEBUG_HW_BCHANNEL) printk(KERN_DEBUG "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n", bch->state, protocol, bch->nr, chan); if (bch->nr != chan) { printk(KERN_DEBUG "HFCPCI rxtest wrong channel parameter %x/%x\n", bch->nr, chan); return -EINVAL; } switch (protocol) { case (ISDN_P_B_RAW): bch->state = protocol; hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; if (!tics) hc->hw.int_m1 |= HFCPCI_INTS_B2REC; hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; #ifdef REVERSE_BITORDER hc->hw.cirm |= 0x80; #endif } else { hc->hw.sctrl_r |= SCTRL_B1_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; if (!tics) hc->hw.int_m1 |= HFCPCI_INTS_B1REC; hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; #ifdef REVERSE_BITORDER hc->hw.cirm |= 0x40; #endif } break; case (ISDN_P_B_HDLC): bch->state = protocol; hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0); if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.last_bfifo_cnt[1] = 0; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; hc->hw.int_m1 |= HFCPCI_INTS_B2REC; hc->hw.ctmt &= ~2; hc->hw.conn &= ~0x18; } else { hc->hw.sctrl_r |= SCTRL_B1_ENA; hc->hw.last_bfifo_cnt[0] = 0; hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; hc->hw.int_m1 |= HFCPCI_INTS_B1REC; hc->hw.ctmt &= ~1; hc->hw.conn &= ~0x03; } break; default: printk(KERN_DEBUG "prot not known %x\n", protocol); return -ENOPROTOOPT; } Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); #ifdef REVERSE_BITORDER Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); #endif return 0; } static void deactivate_bchannel(struct bchannel *bch) { struct hfc_pci *hc = bch->hw; u_long flags; spin_lock_irqsave(&hc->lock, flags); mISDN_clear_bchannel(bch); mode_hfcpci(bch, bch->nr, ISDN_P_NONE); spin_unlock_irqrestore(&hc->lock, flags); } /* * Layer 1 B-channel hardware access */ static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { return mISDN_ctrl_bchannel(bch, cq); } static int hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) { struct bchannel *bch = container_of(ch, struct bchannel, ch); struct hfc_pci *hc = bch->hw; int ret = -EINVAL; u_long flags; if (bch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); switch (cmd) { case HW_TESTRX_RAW: spin_lock_irqsave(&hc->lock, flags); ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg); spin_unlock_irqrestore(&hc->lock, flags); break; case HW_TESTRX_HDLC: spin_lock_irqsave(&hc->lock, flags); ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg); spin_unlock_irqrestore(&hc->lock, flags); break; case HW_TESTRX_OFF: spin_lock_irqsave(&hc->lock, flags); mode_hfcpci(bch, bch->nr, ISDN_P_NONE); spin_unlock_irqrestore(&hc->lock, flags); ret = 0; break; case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); deactivate_bchannel(bch); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); ret = 0; break; case CONTROL_CHANNEL: ret = channel_bctrl(bch, arg); break; default: printk(KERN_WARNING "%s: unknown prim(%x)\n", __func__, cmd); } return ret; } /* * Layer2 -> Layer 1 Dchannel data */ static int hfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) { struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); struct dchannel *dch = container_of(dev, struct dchannel, dev); struct hfc_pci *hc = dch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); unsigned int id; u_long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&hc->lock, flags); ret = dchannel_senddata(dch, skb); if (ret > 0) { /* direct TX */ id = hh->id; /* skb can be freed */ hfcpci_fill_dfifo(dch->hw); ret = 0; spin_unlock_irqrestore(&hc->lock, flags); queue_ch_frame(ch, PH_DATA_CNF, id, NULL); } else spin_unlock_irqrestore(&hc->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&hc->lock, flags); if (hc->hw.protocol == ISDN_P_NT_S0) { ret = 0; if (test_bit(HFC_CFG_MASTER, &hc->cfg)) hc->hw.mst_m |= HFCPCI_MASTER; Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); if (test_bit(FLG_ACTIVE, &dch->Flags)) { spin_unlock_irqrestore(&hc->lock, flags); _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); break; } test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags); Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1); } else ret = l1_event(dch->l1, hh->prim); spin_unlock_irqrestore(&hc->lock, flags); break; case PH_DEACTIVATE_REQ: test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); spin_lock_irqsave(&hc->lock, flags); if (hc->hw.protocol == ISDN_P_NT_S0) { /* prepare deactivation */ Write_hfc(hc, HFCPCI_STATES, 0x40); skb_queue_purge(&dch->squeue); if (dch->tx_skb) { dev_kfree_skb(dch->tx_skb); dch->tx_skb = NULL; } dch->tx_idx = 0; if (dch->rx_skb) { dev_kfree_skb(dch->rx_skb); dch->rx_skb = NULL; } test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) del_timer(&dch->timer); #ifdef FIXME if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) dchannel_sched_event(&hc->dch, D_CLEARBUSY); #endif hc->hw.mst_m &= ~HFCPCI_MASTER; Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); ret = 0; } else { ret = l1_event(dch->l1, hh->prim); } spin_unlock_irqrestore(&hc->lock, flags); break; } if (!ret) dev_kfree_skb(skb); return ret; } /* * Layer2 -> Layer 1 Bchannel data */ static int hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) { struct bchannel *bch = container_of(ch, struct bchannel, ch); struct hfc_pci *hc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: spin_lock_irqsave(&hc->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ hfcpci_fill_fifo(bch); ret = 0; } spin_unlock_irqrestore(&hc->lock, flags); return ret; case PH_ACTIVATE_REQ: spin_lock_irqsave(&hc->lock, flags); if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) ret = mode_hfcpci(bch, bch->nr, ch->protocol); else ret = 0; spin_unlock_irqrestore(&hc->lock, flags); if (!ret) _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL); break; case PH_DEACTIVATE_REQ: deactivate_bchannel(bch); _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL); ret = 0; break; } if (!ret) dev_kfree_skb(skb); return ret; } /* * called for card init message */ static void inithfcpci(struct hfc_pci *hc) { printk(KERN_DEBUG "inithfcpci: entered\n"); hc->dch.timer.function = (void *) hfcpci_dbusy_timer; hc->dch.timer.data = (long) &hc->dch; init_timer(&hc->dch.timer); hc->chanlimit = 2; mode_hfcpci(&hc->bch[0], 1, -1); mode_hfcpci(&hc->bch[1], 2, -1); } static int init_card(struct hfc_pci *hc) { int cnt = 3; u_long flags; printk(KERN_DEBUG "init_card: entered\n"); spin_lock_irqsave(&hc->lock, flags); disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) { printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", hc->irq); return -EIO; } spin_lock_irqsave(&hc->lock, flags); reset_hfcpci(hc); while (cnt) { inithfcpci(hc); /* * Finally enable IRQ output * this is only allowed, if an IRQ routine is already * established for this HFC, so don't do that earlier */ enable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); /* Timeout 80ms */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80 * HZ) / 1000); printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", hc->irq, hc->irqcnt); /* now switch timer interrupt off */ spin_lock_irqsave(&hc->lock, flags); hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* reinit mode reg */ Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); if (!hc->irqcnt) { printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts " "during init %d\n", hc->irq, 4 - cnt); if (cnt == 1) break; else { reset_hfcpci(hc); cnt--; } } else { spin_unlock_irqrestore(&hc->lock, flags); hc->initdone = 1; return 0; } } disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); free_irq(hc->irq, hc); return -EIO; } static int channel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq) { int ret = 0; u_char slot; switch (cq->op) { case MISDN_CTRL_GETOP: cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* channel 0 disabled loop */ if (cq->channel < 0 || cq->channel > 2) { ret = -EINVAL; break; } if (cq->channel & 1) { if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) slot = 0xC0; else slot = 0x80; printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", __func__, slot); Write_hfc(hc, HFCPCI_B1_SSL, slot); Write_hfc(hc, HFCPCI_B1_RSL, slot); hc->hw.conn = (hc->hw.conn & ~7) | 6; Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); } if (cq->channel & 2) { if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) slot = 0xC1; else slot = 0x81; printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", __func__, slot); Write_hfc(hc, HFCPCI_B2_SSL, slot); Write_hfc(hc, HFCPCI_B2_RSL, slot); hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30; Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); } if (cq->channel & 3) hc->hw.trm |= 0x80; /* enable IOM-loop */ else { hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); hc->hw.trm &= 0x7f; /* disable IOM-loop */ } Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); break; case MISDN_CTRL_CONNECT: if (cq->channel == cq->p1) { ret = -EINVAL; break; } if (cq->channel < 1 || cq->channel > 2 || cq->p1 < 1 || cq->p1 > 2) { ret = -EINVAL; break; } if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) slot = 0xC0; else slot = 0x80; printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", __func__, slot); Write_hfc(hc, HFCPCI_B1_SSL, slot); Write_hfc(hc, HFCPCI_B2_RSL, slot); if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) slot = 0xC1; else slot = 0x81; printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", __func__, slot); Write_hfc(hc, HFCPCI_B2_SSL, slot); Write_hfc(hc, HFCPCI_B1_RSL, slot); hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36; Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); hc->hw.trm |= 0x80; Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); break; case MISDN_CTRL_DISCONNECT: hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09; Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); hc->hw.trm &= 0x7f; /* disable IOM-loop */ break; case MISDN_CTRL_L1_TIMER3: ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); ret = -EINVAL; break; } return ret; } static int open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, struct channel_req *rq) { int err = 0; if (debug & DEBUG_HW_OPEN) printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__, hc->dch.dev.id, __builtin_return_address(0)); if (rq->protocol == ISDN_P_NONE) return -EINVAL; if (rq->adr.channel == 1) { /* TODO: E-Channel */ return -EINVAL; } if (!hc->initdone) { if (rq->protocol == ISDN_P_TE_S0) { err = create_l1(&hc->dch, hfc_l1callback); if (err) return err; } hc->hw.protocol = rq->protocol; ch->protocol = rq->protocol; err = init_card(hc); if (err) return err; } else { if (rq->protocol != ch->protocol) { if (hc->hw.protocol == ISDN_P_TE_S0) l1_event(hc->dch.l1, CLOSE_CHANNEL); if (rq->protocol == ISDN_P_TE_S0) { err = create_l1(&hc->dch, hfc_l1callback); if (err) return err; } hc->hw.protocol = rq->protocol; ch->protocol = rq->protocol; hfcpci_setmode(hc); } } if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) || ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) { _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL); } rq->ch = ch; if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s:cannot get module\n", __func__); return 0; } static int open_bchannel(struct hfc_pci *hc, struct channel_req *rq) { struct bchannel *bch; if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; bch = &hc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; /* TODO: E-channel */ if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s:cannot get module\n", __func__); return 0; } /* * device control function */ static int hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) { struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); struct dchannel *dch = container_of(dev, struct dchannel, dev); struct hfc_pci *hc = dch->hw; struct channel_req *rq; int err = 0; if (dch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); switch (cmd) { case OPEN_CHANNEL: rq = arg; if ((rq->protocol == ISDN_P_TE_S0) || (rq->protocol == ISDN_P_NT_S0)) err = open_dchannel(hc, ch, rq); else err = open_bchannel(hc, rq); break; case CLOSE_CHANNEL: if (debug & DEBUG_HW_OPEN) printk(KERN_DEBUG "%s: dev(%d) close from %p\n", __func__, hc->dch.dev.id, __builtin_return_address(0)); module_put(THIS_MODULE); break; case CONTROL_CHANNEL: err = channel_ctrl(hc, arg); break; default: if (dch->debug & DEBUG_HW) printk(KERN_DEBUG "%s: unknown command %x\n", __func__, cmd); return -EINVAL; } return err; } static int setup_hw(struct hfc_pci *hc) { void *buffer; printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision); hc->hw.cirm = 0; hc->dch.state = 0; pci_set_master(hc->pdev); if (!hc->irq) { printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); return 1; } hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start; if (!hc->hw.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return 1; } /* Allocate memory for FIFOS */ /* the memory needs to be on a 32k boundary within the first 4G */ pci_set_dma_mask(hc->pdev, 0xFFFF8000); buffer = pci_alloc_consistent(hc->pdev, 0x8000, &hc->hw.dmahandle); /* We silently assume the address is okay if nonzero */ if (!buffer) { printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); return 1; } hc->hw.fifos = buffer; pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle); hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); printk(KERN_INFO "HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n", (u_long) hc->hw.pci_io, (u_long) hc->hw.fifos, (u_long) hc->hw.dmahandle, hc->irq, HZ); /* enable memory mapped ports, disable busmaster */ pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO); hc->hw.int_m2 = 0; disable_hwirq(hc); hc->hw.int_m1 = 0; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* At this point the needed PCI config is done */ /* fifos are still not enabled */ hc->hw.timer.function = (void *) hfcpci_Timer; hc->hw.timer.data = (long) hc; init_timer(&hc->hw.timer); /* default PCM master */ test_and_set_bit(HFC_CFG_MASTER, &hc->cfg); return 0; } static void release_card(struct hfc_pci *hc) { u_long flags; spin_lock_irqsave(&hc->lock, flags); hc->hw.int_m2 = 0; /* interrupt output off ! */ disable_hwirq(hc); mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE); mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE); if (hc->dch.timer.function != NULL) { del_timer(&hc->dch.timer); hc->dch.timer.function = NULL; } spin_unlock_irqrestore(&hc->lock, flags); if (hc->hw.protocol == ISDN_P_TE_S0) l1_event(hc->dch.l1, CLOSE_CHANNEL); if (hc->initdone) free_irq(hc->irq, hc); release_io_hfcpci(hc); /* must release after free_irq! */ mISDN_unregister_device(&hc->dch.dev); mISDN_freebchannel(&hc->bch[1]); mISDN_freebchannel(&hc->bch[0]); mISDN_freedchannel(&hc->dch); pci_set_drvdata(hc->pdev, NULL); kfree(hc); } static int setup_card(struct hfc_pci *card) { int err = -EINVAL; u_int i; char name[MISDN_MAX_IDLEN]; card->dch.debug = debug; spin_lock_init(&card->lock); mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); card->dch.hw = card; card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); card->dch.dev.D.send = hfcpci_l2l1D; card->dch.dev.D.ctrl = hfc_dctrl; card->dch.dev.nrbchan = 2; for (i = 0; i < 2; i++) { card->bch[i].nr = i + 1; set_channelmap(i + 1, card->dch.dev.channelmap); card->bch[i].debug = debug; mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); card->bch[i].hw = card; card->bch[i].ch.send = hfcpci_l2l1B; card->bch[i].ch.ctrl = hfc_bctrl; card->bch[i].ch.nr = i + 1; list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels); } err = setup_hw(card); if (err) goto error; snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); if (err) goto error; HFC_cnt++; printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); return 0; error: mISDN_freebchannel(&card->bch[1]); mISDN_freebchannel(&card->bch[0]); mISDN_freedchannel(&card->dch); kfree(card); return err; } /* private data in the PCI devices list */ struct _hfc_map { u_int subtype; u_int flag; char *name; }; static const struct _hfc_map hfc_map[] = { {HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"}, {HFC_CCD_B000, 0, "Billion B000"}, {HFC_CCD_B006, 0, "Billion B006"}, {HFC_CCD_B007, 0, "Billion B007"}, {HFC_CCD_B008, 0, "Billion B008"}, {HFC_CCD_B009, 0, "Billion B009"}, {HFC_CCD_B00A, 0, "Billion B00A"}, {HFC_CCD_B00B, 0, "Billion B00B"}, {HFC_CCD_B00C, 0, "Billion B00C"}, {HFC_CCD_B100, 0, "Seyeon B100"}, {HFC_CCD_B700, 0, "Primux II S0 B700"}, {HFC_CCD_B701, 0, "Primux II S0 NT B701"}, {HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"}, {HFC_ASUS_0675, 0, "Asuscom/Askey 675"}, {HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"}, {HFC_BERKOM_A1T, 0, "German telekom A1T"}, {HFC_ANIGMA_MC145575, 0, "Motorola MC145575"}, {HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"}, {HFC_DIGI_DF_M_IOM2_E, 0, "Digi International DataFire Micro V IOM2 (Europe)"}, {HFC_DIGI_DF_M_E, 0, "Digi International DataFire Micro V (Europe)"}, {HFC_DIGI_DF_M_IOM2_A, 0, "Digi International DataFire Micro V IOM2 (North America)"}, {HFC_DIGI_DF_M_A, 0, "Digi International DataFire Micro V (North America)"}, {HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"}, {}, }; static struct pci_device_id hfc_ids[] = { { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0), (unsigned long) &hfc_map[0] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000), (unsigned long) &hfc_map[1] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006), (unsigned long) &hfc_map[2] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007), (unsigned long) &hfc_map[3] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008), (unsigned long) &hfc_map[4] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009), (unsigned long) &hfc_map[5] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A), (unsigned long) &hfc_map[6] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B), (unsigned long) &hfc_map[7] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C), (unsigned long) &hfc_map[8] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100), (unsigned long) &hfc_map[9] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700), (unsigned long) &hfc_map[10] }, { PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701), (unsigned long) &hfc_map[11] }, { PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1), (unsigned long) &hfc_map[12] }, { PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675), (unsigned long) &hfc_map[13] }, { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT), (unsigned long) &hfc_map[14] }, { PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T), (unsigned long) &hfc_map[15] }, { PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575), (unsigned long) &hfc_map[16] }, { PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0), (unsigned long) &hfc_map[17] }, { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E), (unsigned long) &hfc_map[18] }, { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E), (unsigned long) &hfc_map[19] }, { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A), (unsigned long) &hfc_map[20] }, { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A), (unsigned long) &hfc_map[21] }, { PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2), (unsigned long) &hfc_map[22] }, {}, }; static int hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = -ENOMEM; struct hfc_pci *card; struct _hfc_map *m = (struct _hfc_map *)ent->driver_data; card = kzalloc(sizeof(struct hfc_pci), GFP_ATOMIC); if (!card) { printk(KERN_ERR "No kmem for HFC card\n"); return err; } card->pdev = pdev; card->subtype = m->subtype; err = pci_enable_device(pdev); if (err) { kfree(card); return err; } printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n", m->name, pci_name(pdev)); card->irq = pdev->irq; pci_set_drvdata(pdev, card); err = setup_card(card); if (err) pci_set_drvdata(pdev, NULL); return err; } static void hfc_remove_pci(struct pci_dev *pdev) { struct hfc_pci *card = pci_get_drvdata(pdev); if (card) release_card(card); else if (debug) printk(KERN_DEBUG "%s: drvdata already removed\n", __func__); } static struct pci_driver hfc_driver = { .name = "hfcpci", .probe = hfc_probe, .remove = hfc_remove_pci, .id_table = hfc_ids, }; static int _hfcpci_softirq(struct device *dev, void *arg) { struct hfc_pci *hc = dev_get_drvdata(dev); struct bchannel *bch; if (hc == NULL) return 0; if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { spin_lock(&hc->lock); bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ main_rec_hfcpci(bch); tx_birq(bch); } bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ main_rec_hfcpci(bch); tx_birq(bch); } spin_unlock(&hc->lock); } return 0; } static void hfcpci_softirq(void *arg) { WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, arg, _hfcpci_softirq) != 0); /* if next event would be in the past ... */ if ((s32)(hfc_jiffies + tics - jiffies) <= 0) hfc_jiffies = jiffies + 1; else hfc_jiffies += tics; hfc_tl.expires = hfc_jiffies; add_timer(&hfc_tl); } static int __init HFC_init(void) { int err; if (!poll) poll = HFCPCI_BTRANS_THRESHOLD; if (poll != HFCPCI_BTRANS_THRESHOLD) { tics = (poll * HZ) / 8000; if (tics < 1) tics = 1; poll = (tics * 8000) / HZ; if (poll > 256 || poll < 8) { printk(KERN_ERR "%s: Wrong poll value %d not in range " "of 8..256.\n", __func__, poll); err = -EINVAL; return err; } } if (poll != HFCPCI_BTRANS_THRESHOLD) { printk(KERN_INFO "%s: Using alternative poll value of %d\n", __func__, poll); hfc_tl.function = (void *)hfcpci_softirq; hfc_tl.data = 0; init_timer(&hfc_tl); hfc_tl.expires = jiffies + tics; hfc_jiffies = hfc_tl.expires; add_timer(&hfc_tl); } else tics = 0; /* indicate the use of controller's timer */ err = pci_register_driver(&hfc_driver); if (err) { if (timer_pending(&hfc_tl)) del_timer(&hfc_tl); } return err; } static void __exit HFC_cleanup(void) { if (timer_pending(&hfc_tl)) del_timer(&hfc_tl); pci_unregister_driver(&hfc_driver); } module_init(HFC_init); module_exit(HFC_cleanup); MODULE_DEVICE_TABLE(pci, hfc_ids);