162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * hfcpci.c     low level driver for CCD's hfc-pci based cards
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author     Werner Cornelius (werner@isdn4linux.de)
762306a36Sopenharmony_ci *            based on existing driver for CCD hfc ISA cards
862306a36Sopenharmony_ci *            type approval valid for HFC-S PCI A based card
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright 1999  by Werner Cornelius (werner@isdn-development.de)
1162306a36Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Module options:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * debug:
1662306a36Sopenharmony_ci *	NOTE: only one poll value must be given for all cards
1762306a36Sopenharmony_ci *	See hfc_pci.h for debug flags.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * poll:
2062306a36Sopenharmony_ci *	NOTE: only one poll value must be given for all cards
2162306a36Sopenharmony_ci *	Give the number of samples for each fifo process.
2262306a36Sopenharmony_ci *	By default 128 is used. Decrease to reduce delay, increase to
2362306a36Sopenharmony_ci *	reduce cpu load. If unsure, don't mess with it!
2462306a36Sopenharmony_ci *	A value of 128 will use controller's interrupt. Other values will
2562306a36Sopenharmony_ci *	use kernel timer, because the controller will not allow lower values
2662306a36Sopenharmony_ci *	than 128.
2762306a36Sopenharmony_ci *	Also note that the value depends on the kernel timer frequency.
2862306a36Sopenharmony_ci *	If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible.
2962306a36Sopenharmony_ci *	If the kernel uses 100 Hz, steps of 80 samples are possible.
3062306a36Sopenharmony_ci *	If the kernel uses 300 Hz, steps of about 26 samples are possible.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/interrupt.h>
3462306a36Sopenharmony_ci#include <linux/module.h>
3562306a36Sopenharmony_ci#include <linux/pci.h>
3662306a36Sopenharmony_ci#include <linux/delay.h>
3762306a36Sopenharmony_ci#include <linux/mISDNhw.h>
3862306a36Sopenharmony_ci#include <linux/slab.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "hfc_pci.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const char *hfcpci_revision = "2.0";
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int HFC_cnt;
4562306a36Sopenharmony_cistatic uint debug;
4662306a36Sopenharmony_cistatic uint poll, tics;
4762306a36Sopenharmony_cistatic struct timer_list hfc_tl;
4862306a36Sopenharmony_cistatic unsigned long hfc_jiffies;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciMODULE_AUTHOR("Karsten Keil");
5162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5262306a36Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR);
5362306a36Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cienum {
5662306a36Sopenharmony_ci	HFC_CCD_2BD0,
5762306a36Sopenharmony_ci	HFC_CCD_B000,
5862306a36Sopenharmony_ci	HFC_CCD_B006,
5962306a36Sopenharmony_ci	HFC_CCD_B007,
6062306a36Sopenharmony_ci	HFC_CCD_B008,
6162306a36Sopenharmony_ci	HFC_CCD_B009,
6262306a36Sopenharmony_ci	HFC_CCD_B00A,
6362306a36Sopenharmony_ci	HFC_CCD_B00B,
6462306a36Sopenharmony_ci	HFC_CCD_B00C,
6562306a36Sopenharmony_ci	HFC_CCD_B100,
6662306a36Sopenharmony_ci	HFC_CCD_B700,
6762306a36Sopenharmony_ci	HFC_CCD_B701,
6862306a36Sopenharmony_ci	HFC_ASUS_0675,
6962306a36Sopenharmony_ci	HFC_BERKOM_A1T,
7062306a36Sopenharmony_ci	HFC_BERKOM_TCONCEPT,
7162306a36Sopenharmony_ci	HFC_ANIGMA_MC145575,
7262306a36Sopenharmony_ci	HFC_ZOLTRIX_2BD0,
7362306a36Sopenharmony_ci	HFC_DIGI_DF_M_IOM2_E,
7462306a36Sopenharmony_ci	HFC_DIGI_DF_M_E,
7562306a36Sopenharmony_ci	HFC_DIGI_DF_M_IOM2_A,
7662306a36Sopenharmony_ci	HFC_DIGI_DF_M_A,
7762306a36Sopenharmony_ci	HFC_ABOCOM_2BD1,
7862306a36Sopenharmony_ci	HFC_SITECOM_DC105V2,
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct hfcPCI_hw {
8262306a36Sopenharmony_ci	unsigned char		cirm;
8362306a36Sopenharmony_ci	unsigned char		ctmt;
8462306a36Sopenharmony_ci	unsigned char		clkdel;
8562306a36Sopenharmony_ci	unsigned char		states;
8662306a36Sopenharmony_ci	unsigned char		conn;
8762306a36Sopenharmony_ci	unsigned char		mst_m;
8862306a36Sopenharmony_ci	unsigned char		int_m1;
8962306a36Sopenharmony_ci	unsigned char		int_m2;
9062306a36Sopenharmony_ci	unsigned char		sctrl;
9162306a36Sopenharmony_ci	unsigned char		sctrl_r;
9262306a36Sopenharmony_ci	unsigned char		sctrl_e;
9362306a36Sopenharmony_ci	unsigned char		trm;
9462306a36Sopenharmony_ci	unsigned char		fifo_en;
9562306a36Sopenharmony_ci	unsigned char		bswapped;
9662306a36Sopenharmony_ci	unsigned char		protocol;
9762306a36Sopenharmony_ci	int			nt_timer;
9862306a36Sopenharmony_ci	unsigned char __iomem	*pci_io; /* start of PCI IO memory */
9962306a36Sopenharmony_ci	dma_addr_t		dmahandle;
10062306a36Sopenharmony_ci	void			*fifos; /* FIFO memory */
10162306a36Sopenharmony_ci	int			last_bfifo_cnt[2];
10262306a36Sopenharmony_ci	/* marker saving last b-fifo frame count */
10362306a36Sopenharmony_ci	struct timer_list	timer;
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define	HFC_CFG_MASTER		1
10762306a36Sopenharmony_ci#define HFC_CFG_SLAVE		2
10862306a36Sopenharmony_ci#define	HFC_CFG_PCM		3
10962306a36Sopenharmony_ci#define HFC_CFG_2HFC		4
11062306a36Sopenharmony_ci#define HFC_CFG_SLAVEHFC	5
11162306a36Sopenharmony_ci#define HFC_CFG_NEG_F0		6
11262306a36Sopenharmony_ci#define HFC_CFG_SW_DD_DU	7
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define FLG_HFC_TIMER_T1	16
11562306a36Sopenharmony_ci#define FLG_HFC_TIMER_T3	17
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define NT_T1_COUNT	1120	/* number of 3.125ms interrupts (3.5s) */
11862306a36Sopenharmony_ci#define NT_T3_COUNT	31	/* number of 3.125ms interrupts (97 ms) */
11962306a36Sopenharmony_ci#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */
12062306a36Sopenharmony_ci#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistruct hfc_pci {
12462306a36Sopenharmony_ci	u_char			subtype;
12562306a36Sopenharmony_ci	u_char			chanlimit;
12662306a36Sopenharmony_ci	u_char			initdone;
12762306a36Sopenharmony_ci	u_long			cfg;
12862306a36Sopenharmony_ci	u_int			irq;
12962306a36Sopenharmony_ci	u_int			irqcnt;
13062306a36Sopenharmony_ci	struct pci_dev		*pdev;
13162306a36Sopenharmony_ci	struct hfcPCI_hw	hw;
13262306a36Sopenharmony_ci	spinlock_t		lock;	/* card lock */
13362306a36Sopenharmony_ci	struct dchannel		dch;
13462306a36Sopenharmony_ci	struct bchannel		bch[2];
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* Interface functions */
13862306a36Sopenharmony_cistatic void
13962306a36Sopenharmony_cienable_hwirq(struct hfc_pci *hc)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE;
14262306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic void
14662306a36Sopenharmony_cidisable_hwirq(struct hfc_pci *hc)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE);
14962306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/*
15362306a36Sopenharmony_ci * free hardware resources used by driver
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistatic void
15662306a36Sopenharmony_cirelease_io_hfcpci(struct hfc_pci *hc)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	/* disable memory mapped ports + busmaster */
15962306a36Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, 0);
16062306a36Sopenharmony_ci	del_timer(&hc->hw.timer);
16162306a36Sopenharmony_ci	dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
16262306a36Sopenharmony_ci			  hc->hw.dmahandle);
16362306a36Sopenharmony_ci	iounmap(hc->hw.pci_io);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/*
16762306a36Sopenharmony_ci * set mode (NT or TE)
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_cistatic void
17062306a36Sopenharmony_cihfcpci_setmode(struct hfc_pci *hc)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_NT_S0) {
17362306a36Sopenharmony_ci		hc->hw.clkdel = CLKDEL_NT;	/* ST-Bit delay for NT-Mode */
17462306a36Sopenharmony_ci		hc->hw.sctrl |= SCTRL_MODE_NT;	/* NT-MODE */
17562306a36Sopenharmony_ci		hc->hw.states = 1;		/* G1 */
17662306a36Sopenharmony_ci	} else {
17762306a36Sopenharmony_ci		hc->hw.clkdel = CLKDEL_TE;	/* ST-Bit delay for TE-Mode */
17862306a36Sopenharmony_ci		hc->hw.sctrl &= ~SCTRL_MODE_NT;	/* TE-MODE */
17962306a36Sopenharmony_ci		hc->hw.states = 2;		/* F2 */
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
18262306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states);
18362306a36Sopenharmony_ci	udelay(10);
18462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */
18562306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/*
18962306a36Sopenharmony_ci * function called to reset the HFC PCI chip. A complete software reset of chip
19062306a36Sopenharmony_ci * and fifos is done.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic void
19362306a36Sopenharmony_cireset_hfcpci(struct hfc_pci *hc)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	u_char	val;
19662306a36Sopenharmony_ci	int	cnt = 0;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	printk(KERN_DEBUG "reset_hfcpci: entered\n");
19962306a36Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_CHIP_ID);
20062306a36Sopenharmony_ci	printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
20162306a36Sopenharmony_ci	/* enable memory mapped ports, disable busmaster */
20262306a36Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
20362306a36Sopenharmony_ci	disable_hwirq(hc);
20462306a36Sopenharmony_ci	/* enable memory ports + busmaster */
20562306a36Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND,
20662306a36Sopenharmony_ci			      PCI_ENA_MEMIO + PCI_ENA_MASTER);
20762306a36Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_STATUS);
20862306a36Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
20962306a36Sopenharmony_ci	hc->hw.cirm = HFCPCI_RESET;	/* Reset On */
21062306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
21162306a36Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
21262306a36Sopenharmony_ci	mdelay(10);			/* Timeout 10ms */
21362306a36Sopenharmony_ci	hc->hw.cirm = 0;		/* Reset Off */
21462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
21562306a36Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_STATUS);
21662306a36Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val);
21762306a36Sopenharmony_ci	while (cnt < 50000) { /* max 50000 us */
21862306a36Sopenharmony_ci		udelay(5);
21962306a36Sopenharmony_ci		cnt += 5;
22062306a36Sopenharmony_ci		val = Read_hfc(hc, HFCPCI_STATUS);
22162306a36Sopenharmony_ci		if (!(val & 2))
22262306a36Sopenharmony_ci			break;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	hc->hw.fifo_en = 0x30;	/* only D fifos enabled */
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	hc->hw.bswapped = 0;	/* no exchange */
22962306a36Sopenharmony_ci	hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
23062306a36Sopenharmony_ci	hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
23162306a36Sopenharmony_ci	hc->hw.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
23262306a36Sopenharmony_ci	hc->hw.sctrl_r = 0;
23362306a36Sopenharmony_ci	hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE;	/* S/T Auto awake */
23462306a36Sopenharmony_ci	hc->hw.mst_m = 0;
23562306a36Sopenharmony_ci	if (test_bit(HFC_CFG_MASTER, &hc->cfg))
23662306a36Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_MASTER;	/* HFC Master Mode */
23762306a36Sopenharmony_ci	if (test_bit(HFC_CFG_NEG_F0, &hc->cfg))
23862306a36Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_F0_NEGATIV;
23962306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
24062306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
24162306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
24262306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
24562306a36Sopenharmony_ci		HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
24662306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Clear already pending ints */
24962306a36Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_INT_S1);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* set NT/TE mode */
25262306a36Sopenharmony_ci	hfcpci_setmode(hc);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
25562306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * Init GCI/IOM2 in master mode
25962306a36Sopenharmony_ci	 * Slots 0 and 1 are set for B-chan 1 and 2
26062306a36Sopenharmony_ci	 * D- and monitor/CI channel are not enabled
26162306a36Sopenharmony_ci	 * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC
26262306a36Sopenharmony_ci	 * STIO2 is used as data input, B1+B2 from IOM->ST
26362306a36Sopenharmony_ci	 * ST B-channel send disabled -> continuous 1s
26462306a36Sopenharmony_ci	 * The IOM slots are always enabled
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
26762306a36Sopenharmony_ci		/* set data flow directions: connect B1,B2: HFC to/from PCM */
26862306a36Sopenharmony_ci		hc->hw.conn = 0x09;
26962306a36Sopenharmony_ci	} else {
27062306a36Sopenharmony_ci		hc->hw.conn = 0x36;	/* set data flow directions */
27162306a36Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
27262306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, 0xC0);
27362306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, 0xC1);
27462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, 0xC0);
27562306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, 0xC1);
27662306a36Sopenharmony_ci		} else {
27762306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, 0x80);
27862306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, 0x81);
27962306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, 0x80);
28062306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, 0x81);
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
28462306a36Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_INT_S2);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/*
28862306a36Sopenharmony_ci * Timer function called when kernel timer expires
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistatic void
29162306a36Sopenharmony_cihfcpci_Timer(struct timer_list *t)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct hfc_pci *hc = from_timer(hc, t, hw.timer);
29462306a36Sopenharmony_ci	hc->hw.timer.expires = jiffies + 75;
29562306a36Sopenharmony_ci	/* WD RESET */
29662306a36Sopenharmony_ci/*
29762306a36Sopenharmony_ci *	WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80);
29862306a36Sopenharmony_ci *	add_timer(&hc->hw.timer);
29962306a36Sopenharmony_ci */
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/*
30462306a36Sopenharmony_ci * select a b-channel entry matching and active
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_cistatic struct bchannel *
30762306a36Sopenharmony_ciSel_BCS(struct hfc_pci *hc, int channel)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) &&
31062306a36Sopenharmony_ci	    (hc->bch[0].nr & channel))
31162306a36Sopenharmony_ci		return &hc->bch[0];
31262306a36Sopenharmony_ci	else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) &&
31362306a36Sopenharmony_ci		 (hc->bch[1].nr & channel))
31462306a36Sopenharmony_ci		return &hc->bch[1];
31562306a36Sopenharmony_ci	else
31662306a36Sopenharmony_ci		return NULL;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/*
32062306a36Sopenharmony_ci * clear the desired B-channel rx fifo
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic void
32362306a36Sopenharmony_cihfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	u_char		fifo_state;
32662306a36Sopenharmony_ci	struct bzfifo	*bzr;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (fifo) {
32962306a36Sopenharmony_ci		bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
33062306a36Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX;
33162306a36Sopenharmony_ci	} else {
33262306a36Sopenharmony_ci		bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
33362306a36Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci	if (fifo_state)
33662306a36Sopenharmony_ci		hc->hw.fifo_en ^= fifo_state;
33762306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
33862306a36Sopenharmony_ci	hc->hw.last_bfifo_cnt[fifo] = 0;
33962306a36Sopenharmony_ci	bzr->f1 = MAX_B_FRAMES;
34062306a36Sopenharmony_ci	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
34162306a36Sopenharmony_ci	bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
34262306a36Sopenharmony_ci	bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16(
34362306a36Sopenharmony_ci		le16_to_cpu(bzr->za[MAX_B_FRAMES].z1));
34462306a36Sopenharmony_ci	if (fifo_state)
34562306a36Sopenharmony_ci		hc->hw.fifo_en |= fifo_state;
34662306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * clear the desired B-channel tx fifo
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_cistatic void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	u_char		fifo_state;
35562306a36Sopenharmony_ci	struct bzfifo	*bzt;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (fifo) {
35862306a36Sopenharmony_ci		bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
35962306a36Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX;
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci		bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
36262306a36Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	if (fifo_state)
36562306a36Sopenharmony_ci		hc->hw.fifo_en ^= fifo_state;
36662306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
36762306a36Sopenharmony_ci	if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
36862306a36Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) "
36962306a36Sopenharmony_ci		       "z1(%x) z2(%x) state(%x)\n",
37062306a36Sopenharmony_ci		       fifo, bzt->f1, bzt->f2,
37162306a36Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
37262306a36Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z2),
37362306a36Sopenharmony_ci		       fifo_state);
37462306a36Sopenharmony_ci	bzt->f2 = MAX_B_FRAMES;
37562306a36Sopenharmony_ci	bzt->f1 = bzt->f2;	/* init F pointers to remain constant */
37662306a36Sopenharmony_ci	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
37762306a36Sopenharmony_ci	bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2);
37862306a36Sopenharmony_ci	if (fifo_state)
37962306a36Sopenharmony_ci		hc->hw.fifo_en |= fifo_state;
38062306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
38162306a36Sopenharmony_ci	if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
38262306a36Sopenharmony_ci		printk(KERN_DEBUG
38362306a36Sopenharmony_ci		       "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n",
38462306a36Sopenharmony_ci		       fifo, bzt->f1, bzt->f2,
38562306a36Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
38662306a36Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z2));
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/*
39062306a36Sopenharmony_ci * read a complete B-frame out of the buffer
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_cistatic void
39362306a36Sopenharmony_cihfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
39462306a36Sopenharmony_ci		   u_char *bdata, int count)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	u_char		*ptr, *ptr1, new_f2;
39762306a36Sopenharmony_ci	int		maxlen, new_z2;
39862306a36Sopenharmony_ci	struct zt	*zp;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
40162306a36Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_empty_fifo\n");
40262306a36Sopenharmony_ci	zp = &bz->za[bz->f2];	/* point to Z-Regs */
40362306a36Sopenharmony_ci	new_z2 = le16_to_cpu(zp->z2) + count;	/* new position in fifo */
40462306a36Sopenharmony_ci	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
40562306a36Sopenharmony_ci		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
40662306a36Sopenharmony_ci	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
40762306a36Sopenharmony_ci	if ((count > MAX_DATA_SIZE + 3) || (count < 4) ||
40862306a36Sopenharmony_ci	    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
40962306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW)
41062306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet "
41162306a36Sopenharmony_ci			       "invalid length %d or crc\n", count);
41262306a36Sopenharmony_ci#ifdef ERROR_STATISTIC
41362306a36Sopenharmony_ci		bch->err_inv++;
41462306a36Sopenharmony_ci#endif
41562306a36Sopenharmony_ci		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
41662306a36Sopenharmony_ci		bz->f2 = new_f2;	/* next buffer */
41762306a36Sopenharmony_ci	} else {
41862306a36Sopenharmony_ci		bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC);
41962306a36Sopenharmony_ci		if (!bch->rx_skb) {
42062306a36Sopenharmony_ci			printk(KERN_WARNING "HFCPCI: receive out of memory\n");
42162306a36Sopenharmony_ci			return;
42262306a36Sopenharmony_ci		}
42362306a36Sopenharmony_ci		count -= 3;
42462306a36Sopenharmony_ci		ptr = skb_put(bch->rx_skb, count);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
42762306a36Sopenharmony_ci			maxlen = count;		/* complete transfer */
42862306a36Sopenharmony_ci		else
42962306a36Sopenharmony_ci			maxlen = B_FIFO_SIZE + B_SUB_VAL -
43062306a36Sopenharmony_ci				le16_to_cpu(zp->z2);	/* maximum */
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);
43362306a36Sopenharmony_ci		/* start of data */
43462306a36Sopenharmony_ci		memcpy(ptr, ptr1, maxlen);	/* copy data */
43562306a36Sopenharmony_ci		count -= maxlen;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		if (count) {	/* rest remaining */
43862306a36Sopenharmony_ci			ptr += maxlen;
43962306a36Sopenharmony_ci			ptr1 = bdata;	/* start of buffer */
44062306a36Sopenharmony_ci			memcpy(ptr, ptr1, count);	/* rest */
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
44362306a36Sopenharmony_ci		bz->f2 = new_f2;	/* next buffer */
44462306a36Sopenharmony_ci		recv_Bchannel(bch, MISDN_ID_ANY, false);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/*
44962306a36Sopenharmony_ci * D-channel receive procedure
45062306a36Sopenharmony_ci */
45162306a36Sopenharmony_cistatic int
45262306a36Sopenharmony_cireceive_dmsg(struct hfc_pci *hc)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct dchannel	*dch = &hc->dch;
45562306a36Sopenharmony_ci	int		maxlen;
45662306a36Sopenharmony_ci	int		rcnt, total;
45762306a36Sopenharmony_ci	int		count = 5;
45862306a36Sopenharmony_ci	u_char		*ptr, *ptr1;
45962306a36Sopenharmony_ci	struct dfifo	*df;
46062306a36Sopenharmony_ci	struct zt	*zp;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx;
46362306a36Sopenharmony_ci	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
46462306a36Sopenharmony_ci		zp = &df->za[df->f2 & D_FREG_MASK];
46562306a36Sopenharmony_ci		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
46662306a36Sopenharmony_ci		if (rcnt < 0)
46762306a36Sopenharmony_ci			rcnt += D_FIFO_SIZE;
46862306a36Sopenharmony_ci		rcnt++;
46962306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
47062306a36Sopenharmony_ci			printk(KERN_DEBUG
47162306a36Sopenharmony_ci			       "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n",
47262306a36Sopenharmony_ci			       df->f1, df->f2,
47362306a36Sopenharmony_ci			       le16_to_cpu(zp->z1),
47462306a36Sopenharmony_ci			       le16_to_cpu(zp->z2),
47562306a36Sopenharmony_ci			       rcnt);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
47862306a36Sopenharmony_ci		    (df->data[le16_to_cpu(zp->z1)])) {
47962306a36Sopenharmony_ci			if (dch->debug & DEBUG_HW)
48062306a36Sopenharmony_ci				printk(KERN_DEBUG
48162306a36Sopenharmony_ci				       "empty_fifo hfcpci packet inv. len "
48262306a36Sopenharmony_ci				       "%d or crc %d\n",
48362306a36Sopenharmony_ci				       rcnt,
48462306a36Sopenharmony_ci				       df->data[le16_to_cpu(zp->z1)]);
48562306a36Sopenharmony_ci#ifdef ERROR_STATISTIC
48662306a36Sopenharmony_ci			cs->err_rx++;
48762306a36Sopenharmony_ci#endif
48862306a36Sopenharmony_ci			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
48962306a36Sopenharmony_ci				(MAX_D_FRAMES + 1);	/* next buffer */
49062306a36Sopenharmony_ci			df->za[df->f2 & D_FREG_MASK].z2 =
49162306a36Sopenharmony_ci				cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) &
49262306a36Sopenharmony_ci					    (D_FIFO_SIZE - 1));
49362306a36Sopenharmony_ci		} else {
49462306a36Sopenharmony_ci			dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
49562306a36Sopenharmony_ci			if (!dch->rx_skb) {
49662306a36Sopenharmony_ci				printk(KERN_WARNING
49762306a36Sopenharmony_ci				       "HFC-PCI: D receive out of memory\n");
49862306a36Sopenharmony_ci				break;
49962306a36Sopenharmony_ci			}
50062306a36Sopenharmony_ci			total = rcnt;
50162306a36Sopenharmony_ci			rcnt -= 3;
50262306a36Sopenharmony_ci			ptr = skb_put(dch->rx_skb, rcnt);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci			if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE)
50562306a36Sopenharmony_ci				maxlen = rcnt;	/* complete transfer */
50662306a36Sopenharmony_ci			else
50762306a36Sopenharmony_ci				maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);
50862306a36Sopenharmony_ci			/* maximum */
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci			ptr1 = df->data + le16_to_cpu(zp->z2);
51162306a36Sopenharmony_ci			/* start of data */
51262306a36Sopenharmony_ci			memcpy(ptr, ptr1, maxlen);	/* copy data */
51362306a36Sopenharmony_ci			rcnt -= maxlen;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci			if (rcnt) {	/* rest remaining */
51662306a36Sopenharmony_ci				ptr += maxlen;
51762306a36Sopenharmony_ci				ptr1 = df->data;	/* start of buffer */
51862306a36Sopenharmony_ci				memcpy(ptr, ptr1, rcnt);	/* rest */
51962306a36Sopenharmony_ci			}
52062306a36Sopenharmony_ci			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
52162306a36Sopenharmony_ci				(MAX_D_FRAMES + 1);	/* next buffer */
52262306a36Sopenharmony_ci			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((
52362306a36Sopenharmony_ci									      le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
52462306a36Sopenharmony_ci			recv_Dchannel(dch);
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	return 1;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/*
53162306a36Sopenharmony_ci * check for transparent receive data and read max one 'poll' size if avail
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic void
53462306a36Sopenharmony_cihfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
53562306a36Sopenharmony_ci			struct bzfifo *txbz, u_char *bdata)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	__le16	*z1r, *z2r, *z1t, *z2t;
53862306a36Sopenharmony_ci	int	new_z2, fcnt_rx, fcnt_tx, maxlen;
53962306a36Sopenharmony_ci	u_char	*ptr, *ptr1;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	z1r = &rxbz->za[MAX_B_FRAMES].z1;	/* pointer to z reg */
54262306a36Sopenharmony_ci	z2r = z1r + 1;
54362306a36Sopenharmony_ci	z1t = &txbz->za[MAX_B_FRAMES].z1;
54462306a36Sopenharmony_ci	z2t = z1t + 1;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
54762306a36Sopenharmony_ci	if (!fcnt_rx)
54862306a36Sopenharmony_ci		return;	/* no data avail */
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (fcnt_rx <= 0)
55162306a36Sopenharmony_ci		fcnt_rx += B_FIFO_SIZE;	/* bytes actually buffered */
55262306a36Sopenharmony_ci	new_z2 = le16_to_cpu(*z2r) + fcnt_rx;	/* new position in fifo */
55362306a36Sopenharmony_ci	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
55462306a36Sopenharmony_ci		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
55762306a36Sopenharmony_ci	if (fcnt_tx <= 0)
55862306a36Sopenharmony_ci		fcnt_tx += B_FIFO_SIZE;
55962306a36Sopenharmony_ci	/* fcnt_tx contains available bytes in tx-fifo */
56062306a36Sopenharmony_ci	fcnt_tx = B_FIFO_SIZE - fcnt_tx;
56162306a36Sopenharmony_ci	/* remaining bytes to send (bytes in tx-fifo) */
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (test_bit(FLG_RX_OFF, &bch->Flags)) {
56462306a36Sopenharmony_ci		bch->dropcnt += fcnt_rx;
56562306a36Sopenharmony_ci		*z2r = cpu_to_le16(new_z2);
56662306a36Sopenharmony_ci		return;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci	maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
56962306a36Sopenharmony_ci	if (maxlen < 0) {
57062306a36Sopenharmony_ci		pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx);
57162306a36Sopenharmony_ci	} else {
57262306a36Sopenharmony_ci		ptr = skb_put(bch->rx_skb, fcnt_rx);
57362306a36Sopenharmony_ci		if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
57462306a36Sopenharmony_ci			maxlen = fcnt_rx;	/* complete transfer */
57562306a36Sopenharmony_ci		else
57662306a36Sopenharmony_ci			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
57762306a36Sopenharmony_ci		/* maximum */
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
58062306a36Sopenharmony_ci		/* start of data */
58162306a36Sopenharmony_ci		memcpy(ptr, ptr1, maxlen);	/* copy data */
58262306a36Sopenharmony_ci		fcnt_rx -= maxlen;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		if (fcnt_rx) {	/* rest remaining */
58562306a36Sopenharmony_ci			ptr += maxlen;
58662306a36Sopenharmony_ci			ptr1 = bdata;	/* start of buffer */
58762306a36Sopenharmony_ci			memcpy(ptr, ptr1, fcnt_rx);	/* rest */
58862306a36Sopenharmony_ci		}
58962306a36Sopenharmony_ci		recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci	*z2r = cpu_to_le16(new_z2);		/* new position */
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/*
59562306a36Sopenharmony_ci * B-channel main receive routine
59662306a36Sopenharmony_ci */
59762306a36Sopenharmony_cistatic void
59862306a36Sopenharmony_cimain_rec_hfcpci(struct bchannel *bch)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
60162306a36Sopenharmony_ci	int		rcnt, real_fifo;
60262306a36Sopenharmony_ci	int		receive = 0, count = 5;
60362306a36Sopenharmony_ci	struct bzfifo	*txbz, *rxbz;
60462306a36Sopenharmony_ci	u_char		*bdata;
60562306a36Sopenharmony_ci	struct zt	*zp;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
60862306a36Sopenharmony_ci		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
60962306a36Sopenharmony_ci		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
61062306a36Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
61162306a36Sopenharmony_ci		real_fifo = 1;
61262306a36Sopenharmony_ci	} else {
61362306a36Sopenharmony_ci		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
61462306a36Sopenharmony_ci		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
61562306a36Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
61662306a36Sopenharmony_ci		real_fifo = 0;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ciBegin:
61962306a36Sopenharmony_ci	count--;
62062306a36Sopenharmony_ci	if (rxbz->f1 != rxbz->f2) {
62162306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
62262306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
62362306a36Sopenharmony_ci			       bch->nr, rxbz->f1, rxbz->f2);
62462306a36Sopenharmony_ci		zp = &rxbz->za[rxbz->f2];
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
62762306a36Sopenharmony_ci		if (rcnt < 0)
62862306a36Sopenharmony_ci			rcnt += B_FIFO_SIZE;
62962306a36Sopenharmony_ci		rcnt++;
63062306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
63162306a36Sopenharmony_ci			printk(KERN_DEBUG
63262306a36Sopenharmony_ci			       "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
63362306a36Sopenharmony_ci			       bch->nr, le16_to_cpu(zp->z1),
63462306a36Sopenharmony_ci			       le16_to_cpu(zp->z2), rcnt);
63562306a36Sopenharmony_ci		hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
63662306a36Sopenharmony_ci		rcnt = rxbz->f1 - rxbz->f2;
63762306a36Sopenharmony_ci		if (rcnt < 0)
63862306a36Sopenharmony_ci			rcnt += MAX_B_FRAMES + 1;
63962306a36Sopenharmony_ci		if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
64062306a36Sopenharmony_ci			rcnt = 0;
64162306a36Sopenharmony_ci			hfcpci_clear_fifo_rx(hc, real_fifo);
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci		hc->hw.last_bfifo_cnt[real_fifo] = rcnt;
64462306a36Sopenharmony_ci		if (rcnt > 1)
64562306a36Sopenharmony_ci			receive = 1;
64662306a36Sopenharmony_ci		else
64762306a36Sopenharmony_ci			receive = 0;
64862306a36Sopenharmony_ci	} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
64962306a36Sopenharmony_ci		hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
65062306a36Sopenharmony_ci		return;
65162306a36Sopenharmony_ci	} else
65262306a36Sopenharmony_ci		receive = 0;
65362306a36Sopenharmony_ci	if (count && receive)
65462306a36Sopenharmony_ci		goto Begin;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/*
65962306a36Sopenharmony_ci * D-channel send routine
66062306a36Sopenharmony_ci */
66162306a36Sopenharmony_cistatic void
66262306a36Sopenharmony_cihfcpci_fill_dfifo(struct hfc_pci *hc)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct dchannel	*dch = &hc->dch;
66562306a36Sopenharmony_ci	int		fcnt;
66662306a36Sopenharmony_ci	int		count, new_z1, maxlen;
66762306a36Sopenharmony_ci	struct dfifo	*df;
66862306a36Sopenharmony_ci	u_char		*src, *dst, new_f1;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO))
67162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s\n", __func__);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (!dch->tx_skb)
67462306a36Sopenharmony_ci		return;
67562306a36Sopenharmony_ci	count = dch->tx_skb->len - dch->tx_idx;
67662306a36Sopenharmony_ci	if (count <= 0)
67762306a36Sopenharmony_ci		return;
67862306a36Sopenharmony_ci	df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (dch->debug & DEBUG_HW_DFIFO)
68162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__,
68262306a36Sopenharmony_ci		       df->f1, df->f2,
68362306a36Sopenharmony_ci		       le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
68462306a36Sopenharmony_ci	fcnt = df->f1 - df->f2;	/* frame count actually buffered */
68562306a36Sopenharmony_ci	if (fcnt < 0)
68662306a36Sopenharmony_ci		fcnt += (MAX_D_FRAMES + 1);	/* if wrap around */
68762306a36Sopenharmony_ci	if (fcnt > (MAX_D_FRAMES - 1)) {
68862306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
68962306a36Sopenharmony_ci			printk(KERN_DEBUG
69062306a36Sopenharmony_ci			       "hfcpci_fill_Dfifo more as 14 frames\n");
69162306a36Sopenharmony_ci#ifdef ERROR_STATISTIC
69262306a36Sopenharmony_ci		cs->err_tx++;
69362306a36Sopenharmony_ci#endif
69462306a36Sopenharmony_ci		return;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci	/* now determine free bytes in FIFO buffer */
69762306a36Sopenharmony_ci	maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) -
69862306a36Sopenharmony_ci		le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1;
69962306a36Sopenharmony_ci	if (maxlen <= 0)
70062306a36Sopenharmony_ci		maxlen += D_FIFO_SIZE;	/* count now contains available bytes */
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (dch->debug & DEBUG_HW_DCHANNEL)
70362306a36Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n",
70462306a36Sopenharmony_ci		       count, maxlen);
70562306a36Sopenharmony_ci	if (count > maxlen) {
70662306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
70762306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n");
70862306a36Sopenharmony_ci		return;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci	new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) &
71162306a36Sopenharmony_ci		(D_FIFO_SIZE - 1);
71262306a36Sopenharmony_ci	new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
71362306a36Sopenharmony_ci	src = dch->tx_skb->data + dch->tx_idx;	/* source pointer */
71462306a36Sopenharmony_ci	dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
71562306a36Sopenharmony_ci	maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
71662306a36Sopenharmony_ci	/* end fifo */
71762306a36Sopenharmony_ci	if (maxlen > count)
71862306a36Sopenharmony_ci		maxlen = count;	/* limit size */
71962306a36Sopenharmony_ci	memcpy(dst, src, maxlen);	/* first copy */
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	count -= maxlen;	/* remaining bytes */
72262306a36Sopenharmony_ci	if (count) {
72362306a36Sopenharmony_ci		dst = df->data;	/* start of buffer */
72462306a36Sopenharmony_ci		src += maxlen;	/* new position */
72562306a36Sopenharmony_ci		memcpy(dst, src, count);
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci	df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
72862306a36Sopenharmony_ci	/* for next buffer */
72962306a36Sopenharmony_ci	df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
73062306a36Sopenharmony_ci	/* new pos actual buffer */
73162306a36Sopenharmony_ci	df->f1 = new_f1;	/* next frame */
73262306a36Sopenharmony_ci	dch->tx_idx = dch->tx_skb->len;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci/*
73662306a36Sopenharmony_ci * B-channel send routine
73762306a36Sopenharmony_ci */
73862306a36Sopenharmony_cistatic void
73962306a36Sopenharmony_cihfcpci_fill_fifo(struct bchannel *bch)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
74262306a36Sopenharmony_ci	int		maxlen, fcnt;
74362306a36Sopenharmony_ci	int		count, new_z1;
74462306a36Sopenharmony_ci	struct bzfifo	*bz;
74562306a36Sopenharmony_ci	u_char		*bdata;
74662306a36Sopenharmony_ci	u_char		new_f1, *src, *dst;
74762306a36Sopenharmony_ci	__le16 *z1t, *z2t;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
75062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s\n", __func__);
75162306a36Sopenharmony_ci	if ((!bch->tx_skb) || bch->tx_skb->len == 0) {
75262306a36Sopenharmony_ci		if (!test_bit(FLG_FILLEMPTY, &bch->Flags) &&
75362306a36Sopenharmony_ci		    !test_bit(FLG_TRANSPARENT, &bch->Flags))
75462306a36Sopenharmony_ci			return;
75562306a36Sopenharmony_ci		count = HFCPCI_FILLEMPTY;
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		count = bch->tx_skb->len - bch->tx_idx;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
76062306a36Sopenharmony_ci		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
76162306a36Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2;
76262306a36Sopenharmony_ci	} else {
76362306a36Sopenharmony_ci		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
76462306a36Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
76862306a36Sopenharmony_ci		z1t = &bz->za[MAX_B_FRAMES].z1;
76962306a36Sopenharmony_ci		z2t = z1t + 1;
77062306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
77162306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) "
77262306a36Sopenharmony_ci			       "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count,
77362306a36Sopenharmony_ci			       le16_to_cpu(*z1t), le16_to_cpu(*z2t));
77462306a36Sopenharmony_ci		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
77562306a36Sopenharmony_ci		if (fcnt <= 0)
77662306a36Sopenharmony_ci			fcnt += B_FIFO_SIZE;
77762306a36Sopenharmony_ci		if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
77862306a36Sopenharmony_ci			/* fcnt contains available bytes in fifo */
77962306a36Sopenharmony_ci			if (count > fcnt)
78062306a36Sopenharmony_ci				count = fcnt;
78162306a36Sopenharmony_ci			new_z1 = le16_to_cpu(*z1t) + count;
78262306a36Sopenharmony_ci			/* new buffer Position */
78362306a36Sopenharmony_ci			if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
78462306a36Sopenharmony_ci				new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
78562306a36Sopenharmony_ci			dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
78662306a36Sopenharmony_ci			maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
78762306a36Sopenharmony_ci			/* end of fifo */
78862306a36Sopenharmony_ci			if (bch->debug & DEBUG_HW_BFIFO)
78962306a36Sopenharmony_ci				printk(KERN_DEBUG "hfcpci_FFt fillempty "
79062306a36Sopenharmony_ci				       "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n",
79162306a36Sopenharmony_ci				       fcnt, maxlen, new_z1, dst);
79262306a36Sopenharmony_ci			if (maxlen > count)
79362306a36Sopenharmony_ci				maxlen = count;		/* limit size */
79462306a36Sopenharmony_ci			memset(dst, bch->fill[0], maxlen); /* first copy */
79562306a36Sopenharmony_ci			count -= maxlen;		/* remaining bytes */
79662306a36Sopenharmony_ci			if (count) {
79762306a36Sopenharmony_ci				dst = bdata;		/* start of buffer */
79862306a36Sopenharmony_ci				memset(dst, bch->fill[0], count);
79962306a36Sopenharmony_ci			}
80062306a36Sopenharmony_ci			*z1t = cpu_to_le16(new_z1);	/* now send data */
80162306a36Sopenharmony_ci			return;
80262306a36Sopenharmony_ci		}
80362306a36Sopenharmony_ci		/* fcnt contains available bytes in fifo */
80462306a36Sopenharmony_ci		fcnt = B_FIFO_SIZE - fcnt;
80562306a36Sopenharmony_ci		/* remaining bytes to send (bytes in fifo) */
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	next_t_frame:
80862306a36Sopenharmony_ci		count = bch->tx_skb->len - bch->tx_idx;
80962306a36Sopenharmony_ci		/* maximum fill shall be poll*2 */
81062306a36Sopenharmony_ci		if (count > (poll << 1) - fcnt)
81162306a36Sopenharmony_ci			count = (poll << 1) - fcnt;
81262306a36Sopenharmony_ci		if (count <= 0)
81362306a36Sopenharmony_ci			return;
81462306a36Sopenharmony_ci		/* data is suitable for fifo */
81562306a36Sopenharmony_ci		new_z1 = le16_to_cpu(*z1t) + count;
81662306a36Sopenharmony_ci		/* new buffer Position */
81762306a36Sopenharmony_ci		if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
81862306a36Sopenharmony_ci			new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
81962306a36Sopenharmony_ci		src = bch->tx_skb->data + bch->tx_idx;
82062306a36Sopenharmony_ci		/* source pointer */
82162306a36Sopenharmony_ci		dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
82262306a36Sopenharmony_ci		maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
82362306a36Sopenharmony_ci		/* end of fifo */
82462306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BFIFO)
82562306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) "
82662306a36Sopenharmony_ci			       "maxl(%d) nz1(%x) dst(%p)\n",
82762306a36Sopenharmony_ci			       fcnt, maxlen, new_z1, dst);
82862306a36Sopenharmony_ci		fcnt += count;
82962306a36Sopenharmony_ci		bch->tx_idx += count;
83062306a36Sopenharmony_ci		if (maxlen > count)
83162306a36Sopenharmony_ci			maxlen = count;		/* limit size */
83262306a36Sopenharmony_ci		memcpy(dst, src, maxlen);	/* first copy */
83362306a36Sopenharmony_ci		count -= maxlen;	/* remaining bytes */
83462306a36Sopenharmony_ci		if (count) {
83562306a36Sopenharmony_ci			dst = bdata;	/* start of buffer */
83662306a36Sopenharmony_ci			src += maxlen;	/* new position */
83762306a36Sopenharmony_ci			memcpy(dst, src, count);
83862306a36Sopenharmony_ci		}
83962306a36Sopenharmony_ci		*z1t = cpu_to_le16(new_z1);	/* now send data */
84062306a36Sopenharmony_ci		if (bch->tx_idx < bch->tx_skb->len)
84162306a36Sopenharmony_ci			return;
84262306a36Sopenharmony_ci		dev_kfree_skb_any(bch->tx_skb);
84362306a36Sopenharmony_ci		if (get_next_bframe(bch))
84462306a36Sopenharmony_ci			goto next_t_frame;
84562306a36Sopenharmony_ci		return;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
84862306a36Sopenharmony_ci		printk(KERN_DEBUG
84962306a36Sopenharmony_ci		       "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n",
85062306a36Sopenharmony_ci		       __func__, bch->nr, bz->f1, bz->f2,
85162306a36Sopenharmony_ci		       bz->za[bz->f1].z1);
85262306a36Sopenharmony_ci	fcnt = bz->f1 - bz->f2;	/* frame count actually buffered */
85362306a36Sopenharmony_ci	if (fcnt < 0)
85462306a36Sopenharmony_ci		fcnt += (MAX_B_FRAMES + 1);	/* if wrap around */
85562306a36Sopenharmony_ci	if (fcnt > (MAX_B_FRAMES - 1)) {
85662306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
85762306a36Sopenharmony_ci			printk(KERN_DEBUG
85862306a36Sopenharmony_ci			       "hfcpci_fill_Bfifo more as 14 frames\n");
85962306a36Sopenharmony_ci		return;
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci	/* now determine free bytes in FIFO buffer */
86262306a36Sopenharmony_ci	maxlen = le16_to_cpu(bz->za[bz->f2].z2) -
86362306a36Sopenharmony_ci		le16_to_cpu(bz->za[bz->f1].z1) - 1;
86462306a36Sopenharmony_ci	if (maxlen <= 0)
86562306a36Sopenharmony_ci		maxlen += B_FIFO_SIZE;	/* count now contains available bytes */
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
86862306a36Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n",
86962306a36Sopenharmony_ci		       bch->nr, count, maxlen);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (maxlen < count) {
87262306a36Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
87362306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n");
87462306a36Sopenharmony_ci		return;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci	new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;
87762306a36Sopenharmony_ci	/* new buffer Position */
87862306a36Sopenharmony_ci	if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
87962306a36Sopenharmony_ci		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
88262306a36Sopenharmony_ci	src = bch->tx_skb->data + bch->tx_idx;	/* source pointer */
88362306a36Sopenharmony_ci	dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
88462306a36Sopenharmony_ci	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);
88562306a36Sopenharmony_ci	/* end fifo */
88662306a36Sopenharmony_ci	if (maxlen > count)
88762306a36Sopenharmony_ci		maxlen = count;	/* limit size */
88862306a36Sopenharmony_ci	memcpy(dst, src, maxlen);	/* first copy */
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	count -= maxlen;	/* remaining bytes */
89162306a36Sopenharmony_ci	if (count) {
89262306a36Sopenharmony_ci		dst = bdata;	/* start of buffer */
89362306a36Sopenharmony_ci		src += maxlen;	/* new position */
89462306a36Sopenharmony_ci		memcpy(dst, src, count);
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
89762306a36Sopenharmony_ci	bz->f1 = new_f1;	/* next frame */
89862306a36Sopenharmony_ci	dev_kfree_skb_any(bch->tx_skb);
89962306a36Sopenharmony_ci	get_next_bframe(bch);
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci/*
90562306a36Sopenharmony_ci * handle L1 state changes TE
90662306a36Sopenharmony_ci */
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic void
90962306a36Sopenharmony_ciph_state_te(struct dchannel *dch)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	if (dch->debug)
91262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: TE newstate %x\n",
91362306a36Sopenharmony_ci		       __func__, dch->state);
91462306a36Sopenharmony_ci	switch (dch->state) {
91562306a36Sopenharmony_ci	case 0:
91662306a36Sopenharmony_ci		l1_event(dch->l1, HW_RESET_IND);
91762306a36Sopenharmony_ci		break;
91862306a36Sopenharmony_ci	case 3:
91962306a36Sopenharmony_ci		l1_event(dch->l1, HW_DEACT_IND);
92062306a36Sopenharmony_ci		break;
92162306a36Sopenharmony_ci	case 5:
92262306a36Sopenharmony_ci	case 8:
92362306a36Sopenharmony_ci		l1_event(dch->l1, ANYSIGNAL);
92462306a36Sopenharmony_ci		break;
92562306a36Sopenharmony_ci	case 6:
92662306a36Sopenharmony_ci		l1_event(dch->l1, INFO2);
92762306a36Sopenharmony_ci		break;
92862306a36Sopenharmony_ci	case 7:
92962306a36Sopenharmony_ci		l1_event(dch->l1, INFO4_P8);
93062306a36Sopenharmony_ci		break;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci/*
93562306a36Sopenharmony_ci * handle L1 state changes NT
93662306a36Sopenharmony_ci */
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic void
93962306a36Sopenharmony_cihandle_nt_timer3(struct dchannel *dch) {
94062306a36Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
94362306a36Sopenharmony_ci	hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
94462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
94562306a36Sopenharmony_ci	hc->hw.nt_timer = 0;
94662306a36Sopenharmony_ci	test_and_set_bit(FLG_ACTIVE, &dch->Flags);
94762306a36Sopenharmony_ci	if (test_bit(HFC_CFG_MASTER, &hc->cfg))
94862306a36Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_MASTER;
94962306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
95062306a36Sopenharmony_ci	_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
95162306a36Sopenharmony_ci		    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_cistatic void
95562306a36Sopenharmony_ciph_state_nt(struct dchannel *dch)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	if (dch->debug)
96062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: NT newstate %x\n",
96162306a36Sopenharmony_ci		       __func__, dch->state);
96262306a36Sopenharmony_ci	switch (dch->state) {
96362306a36Sopenharmony_ci	case 2:
96462306a36Sopenharmony_ci		if (hc->hw.nt_timer < 0) {
96562306a36Sopenharmony_ci			hc->hw.nt_timer = 0;
96662306a36Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
96762306a36Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
96862306a36Sopenharmony_ci			hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
96962306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
97062306a36Sopenharmony_ci			/* Clear already pending ints */
97162306a36Sopenharmony_ci			(void) Read_hfc(hc, HFCPCI_INT_S1);
97262306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
97362306a36Sopenharmony_ci			udelay(10);
97462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 4);
97562306a36Sopenharmony_ci			dch->state = 4;
97662306a36Sopenharmony_ci		} else if (hc->hw.nt_timer == 0) {
97762306a36Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
97862306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
97962306a36Sopenharmony_ci			hc->hw.nt_timer = NT_T1_COUNT;
98062306a36Sopenharmony_ci			hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
98162306a36Sopenharmony_ci			hc->hw.ctmt |= HFCPCI_TIM3_125;
98262306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
98362306a36Sopenharmony_ci				  HFCPCI_CLTIMER);
98462306a36Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
98562306a36Sopenharmony_ci			test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags);
98662306a36Sopenharmony_ci			/* allow G2 -> G3 transition */
98762306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
98862306a36Sopenharmony_ci		} else {
98962306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci		break;
99262306a36Sopenharmony_ci	case 1:
99362306a36Sopenharmony_ci		hc->hw.nt_timer = 0;
99462306a36Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
99562306a36Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
99662306a36Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
99762306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
99862306a36Sopenharmony_ci		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
99962306a36Sopenharmony_ci		hc->hw.mst_m &= ~HFCPCI_MASTER;
100062306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
100162306a36Sopenharmony_ci		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
100262306a36Sopenharmony_ci		_queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
100362306a36Sopenharmony_ci			    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
100462306a36Sopenharmony_ci		break;
100562306a36Sopenharmony_ci	case 4:
100662306a36Sopenharmony_ci		hc->hw.nt_timer = 0;
100762306a36Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
100862306a36Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
100962306a36Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
101062306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
101162306a36Sopenharmony_ci		break;
101262306a36Sopenharmony_ci	case 3:
101362306a36Sopenharmony_ci		if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) {
101462306a36Sopenharmony_ci			if (!test_and_clear_bit(FLG_L2_ACTIVATED,
101562306a36Sopenharmony_ci						&dch->Flags)) {
101662306a36Sopenharmony_ci				handle_nt_timer3(dch);
101762306a36Sopenharmony_ci				break;
101862306a36Sopenharmony_ci			}
101962306a36Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
102062306a36Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
102162306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
102262306a36Sopenharmony_ci			hc->hw.nt_timer = NT_T3_COUNT;
102362306a36Sopenharmony_ci			hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
102462306a36Sopenharmony_ci			hc->hw.ctmt |= HFCPCI_TIM3_125;
102562306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
102662306a36Sopenharmony_ci				  HFCPCI_CLTIMER);
102762306a36Sopenharmony_ci		}
102862306a36Sopenharmony_ci		break;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic void
103362306a36Sopenharmony_ciph_state(struct dchannel *dch)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_NT_S0) {
103862306a36Sopenharmony_ci		if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) &&
103962306a36Sopenharmony_ci		    hc->hw.nt_timer < 0)
104062306a36Sopenharmony_ci			handle_nt_timer3(dch);
104162306a36Sopenharmony_ci		else
104262306a36Sopenharmony_ci			ph_state_nt(dch);
104362306a36Sopenharmony_ci	} else
104462306a36Sopenharmony_ci		ph_state_te(dch);
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci/*
104862306a36Sopenharmony_ci * Layer 1 callback function
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_cistatic int
105162306a36Sopenharmony_cihfc_l1callback(struct dchannel *dch, u_int cmd)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	switch (cmd) {
105662306a36Sopenharmony_ci	case INFO3_P8:
105762306a36Sopenharmony_ci	case INFO3_P10:
105862306a36Sopenharmony_ci		if (test_bit(HFC_CFG_MASTER, &hc->cfg))
105962306a36Sopenharmony_ci			hc->hw.mst_m |= HFCPCI_MASTER;
106062306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
106162306a36Sopenharmony_ci		break;
106262306a36Sopenharmony_ci	case HW_RESET_REQ:
106362306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3);
106462306a36Sopenharmony_ci		/* HFC ST 3 */
106562306a36Sopenharmony_ci		udelay(6);
106662306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, 3);	/* HFC ST 2 */
106762306a36Sopenharmony_ci		if (test_bit(HFC_CFG_MASTER, &hc->cfg))
106862306a36Sopenharmony_ci			hc->hw.mst_m |= HFCPCI_MASTER;
106962306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
107062306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
107162306a36Sopenharmony_ci			  HFCPCI_DO_ACTION);
107262306a36Sopenharmony_ci		l1_event(dch->l1, HW_POWERUP_IND);
107362306a36Sopenharmony_ci		break;
107462306a36Sopenharmony_ci	case HW_DEACT_REQ:
107562306a36Sopenharmony_ci		hc->hw.mst_m &= ~HFCPCI_MASTER;
107662306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
107762306a36Sopenharmony_ci		skb_queue_purge(&dch->squeue);
107862306a36Sopenharmony_ci		if (dch->tx_skb) {
107962306a36Sopenharmony_ci			dev_kfree_skb(dch->tx_skb);
108062306a36Sopenharmony_ci			dch->tx_skb = NULL;
108162306a36Sopenharmony_ci		}
108262306a36Sopenharmony_ci		dch->tx_idx = 0;
108362306a36Sopenharmony_ci		if (dch->rx_skb) {
108462306a36Sopenharmony_ci			dev_kfree_skb(dch->rx_skb);
108562306a36Sopenharmony_ci			dch->rx_skb = NULL;
108662306a36Sopenharmony_ci		}
108762306a36Sopenharmony_ci		test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
108862306a36Sopenharmony_ci		if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
108962306a36Sopenharmony_ci			del_timer(&dch->timer);
109062306a36Sopenharmony_ci		break;
109162306a36Sopenharmony_ci	case HW_POWERUP_REQ:
109262306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION);
109362306a36Sopenharmony_ci		break;
109462306a36Sopenharmony_ci	case PH_ACTIVATE_IND:
109562306a36Sopenharmony_ci		test_and_set_bit(FLG_ACTIVE, &dch->Flags);
109662306a36Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
109762306a36Sopenharmony_ci			    GFP_ATOMIC);
109862306a36Sopenharmony_ci		break;
109962306a36Sopenharmony_ci	case PH_DEACTIVATE_IND:
110062306a36Sopenharmony_ci		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
110162306a36Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
110262306a36Sopenharmony_ci			    GFP_ATOMIC);
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	default:
110562306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW)
110662306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
110762306a36Sopenharmony_ci			       __func__, cmd);
110862306a36Sopenharmony_ci		return -1;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci	return 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci/*
111462306a36Sopenharmony_ci * Interrupt handler
111562306a36Sopenharmony_ci */
111662306a36Sopenharmony_cistatic inline void
111762306a36Sopenharmony_citx_birq(struct bchannel *bch)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
112062306a36Sopenharmony_ci		hfcpci_fill_fifo(bch);
112162306a36Sopenharmony_ci	else {
112262306a36Sopenharmony_ci		dev_kfree_skb_any(bch->tx_skb);
112362306a36Sopenharmony_ci		if (get_next_bframe(bch))
112462306a36Sopenharmony_ci			hfcpci_fill_fifo(bch);
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic inline void
112962306a36Sopenharmony_citx_dirq(struct dchannel *dch)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len)
113262306a36Sopenharmony_ci		hfcpci_fill_dfifo(dch->hw);
113362306a36Sopenharmony_ci	else {
113462306a36Sopenharmony_ci		dev_kfree_skb(dch->tx_skb);
113562306a36Sopenharmony_ci		if (get_next_dframe(dch))
113662306a36Sopenharmony_ci			hfcpci_fill_dfifo(dch->hw);
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic irqreturn_t
114162306a36Sopenharmony_cihfcpci_int(int intno, void *dev_id)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct hfc_pci	*hc = dev_id;
114462306a36Sopenharmony_ci	u_char		exval;
114562306a36Sopenharmony_ci	struct bchannel	*bch;
114662306a36Sopenharmony_ci	u_char		val, stat;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	spin_lock(&hc->lock);
114962306a36Sopenharmony_ci	if (!(hc->hw.int_m2 & 0x08)) {
115062306a36Sopenharmony_ci		spin_unlock(&hc->lock);
115162306a36Sopenharmony_ci		return IRQ_NONE; /* not initialised */
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci	stat = Read_hfc(hc, HFCPCI_STATUS);
115462306a36Sopenharmony_ci	if (HFCPCI_ANYINT & stat) {
115562306a36Sopenharmony_ci		val = Read_hfc(hc, HFCPCI_INT_S1);
115662306a36Sopenharmony_ci		if (hc->dch.debug & DEBUG_HW_DCHANNEL)
115762306a36Sopenharmony_ci			printk(KERN_DEBUG
115862306a36Sopenharmony_ci			       "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val);
115962306a36Sopenharmony_ci	} else {
116062306a36Sopenharmony_ci		/* shared */
116162306a36Sopenharmony_ci		spin_unlock(&hc->lock);
116262306a36Sopenharmony_ci		return IRQ_NONE;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci	hc->irqcnt++;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	if (hc->dch.debug & DEBUG_HW_DCHANNEL)
116762306a36Sopenharmony_ci		printk(KERN_DEBUG "HFC-PCI irq %x\n", val);
116862306a36Sopenharmony_ci	val &= hc->hw.int_m1;
116962306a36Sopenharmony_ci	if (val & 0x40) {	/* state machine irq */
117062306a36Sopenharmony_ci		exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
117162306a36Sopenharmony_ci		if (hc->dch.debug & DEBUG_HW_DCHANNEL)
117262306a36Sopenharmony_ci			printk(KERN_DEBUG "ph_state chg %d->%d\n",
117362306a36Sopenharmony_ci			       hc->dch.state, exval);
117462306a36Sopenharmony_ci		hc->dch.state = exval;
117562306a36Sopenharmony_ci		schedule_event(&hc->dch, FLG_PHCHANGE);
117662306a36Sopenharmony_ci		val &= ~0x40;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci	if (val & 0x80) {	/* timer irq */
117962306a36Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
118062306a36Sopenharmony_ci			if ((--hc->hw.nt_timer) < 0)
118162306a36Sopenharmony_ci				schedule_event(&hc->dch, FLG_PHCHANGE);
118262306a36Sopenharmony_ci		}
118362306a36Sopenharmony_ci		val &= ~0x80;
118462306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci	if (val & 0x08) {	/* B1 rx */
118762306a36Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
118862306a36Sopenharmony_ci		if (bch)
118962306a36Sopenharmony_ci			main_rec_hfcpci(bch);
119062306a36Sopenharmony_ci		else if (hc->dch.debug)
119162306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n");
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci	if (val & 0x10) {	/* B2 rx */
119462306a36Sopenharmony_ci		bch = Sel_BCS(hc, 2);
119562306a36Sopenharmony_ci		if (bch)
119662306a36Sopenharmony_ci			main_rec_hfcpci(bch);
119762306a36Sopenharmony_ci		else if (hc->dch.debug)
119862306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n");
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci	if (val & 0x01) {	/* B1 tx */
120162306a36Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
120262306a36Sopenharmony_ci		if (bch)
120362306a36Sopenharmony_ci			tx_birq(bch);
120462306a36Sopenharmony_ci		else if (hc->dch.debug)
120562306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n");
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci	if (val & 0x02) {	/* B2 tx */
120862306a36Sopenharmony_ci		bch = Sel_BCS(hc, 2);
120962306a36Sopenharmony_ci		if (bch)
121062306a36Sopenharmony_ci			tx_birq(bch);
121162306a36Sopenharmony_ci		else if (hc->dch.debug)
121262306a36Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n");
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci	if (val & 0x20)		/* D rx */
121562306a36Sopenharmony_ci		receive_dmsg(hc);
121662306a36Sopenharmony_ci	if (val & 0x04) {	/* D tx */
121762306a36Sopenharmony_ci		if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
121862306a36Sopenharmony_ci			del_timer(&hc->dch.timer);
121962306a36Sopenharmony_ci		tx_dirq(&hc->dch);
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci	spin_unlock(&hc->lock);
122262306a36Sopenharmony_ci	return IRQ_HANDLED;
122362306a36Sopenharmony_ci}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci/*
122662306a36Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function
122762306a36Sopenharmony_ci */
122862306a36Sopenharmony_cistatic void
122962306a36Sopenharmony_cihfcpci_dbusy_timer(struct timer_list *t)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/*
123462306a36Sopenharmony_ci * activate/deactivate hardware for selected channels and mode
123562306a36Sopenharmony_ci */
123662306a36Sopenharmony_cistatic int
123762306a36Sopenharmony_cimode_hfcpci(struct bchannel *bch, int bc, int protocol)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
124062306a36Sopenharmony_ci	int		fifo2;
124162306a36Sopenharmony_ci	u_char		rx_slot = 0, tx_slot = 0, pcm_mode;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
124462306a36Sopenharmony_ci		printk(KERN_DEBUG
124562306a36Sopenharmony_ci		       "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n",
124662306a36Sopenharmony_ci		       bch->state, protocol, bch->nr, bc);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	fifo2 = bc;
124962306a36Sopenharmony_ci	pcm_mode = (bc >> 24) & 0xff;
125062306a36Sopenharmony_ci	if (pcm_mode) { /* PCM SLOT USE */
125162306a36Sopenharmony_ci		if (!test_bit(HFC_CFG_PCM, &hc->cfg))
125262306a36Sopenharmony_ci			printk(KERN_WARNING
125362306a36Sopenharmony_ci			       "%s: pcm channel id without HFC_CFG_PCM\n",
125462306a36Sopenharmony_ci			       __func__);
125562306a36Sopenharmony_ci		rx_slot = (bc >> 8) & 0xff;
125662306a36Sopenharmony_ci		tx_slot = (bc >> 16) & 0xff;
125762306a36Sopenharmony_ci		bc = bc & 0xff;
125862306a36Sopenharmony_ci	} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE))
125962306a36Sopenharmony_ci		printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
126062306a36Sopenharmony_ci		       __func__);
126162306a36Sopenharmony_ci	if (hc->chanlimit > 1) {
126262306a36Sopenharmony_ci		hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
126362306a36Sopenharmony_ci		hc->hw.sctrl_e &= ~0x80;
126462306a36Sopenharmony_ci	} else {
126562306a36Sopenharmony_ci		if (bc & 2) {
126662306a36Sopenharmony_ci			if (protocol != ISDN_P_NONE) {
126762306a36Sopenharmony_ci				hc->hw.bswapped = 1; /* B1 and B2 exchanged */
126862306a36Sopenharmony_ci				hc->hw.sctrl_e |= 0x80;
126962306a36Sopenharmony_ci			} else {
127062306a36Sopenharmony_ci				hc->hw.bswapped = 0; /* B1 and B2 normal mode */
127162306a36Sopenharmony_ci				hc->hw.sctrl_e &= ~0x80;
127262306a36Sopenharmony_ci			}
127362306a36Sopenharmony_ci			fifo2 = 1;
127462306a36Sopenharmony_ci		} else {
127562306a36Sopenharmony_ci			hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
127662306a36Sopenharmony_ci			hc->hw.sctrl_e &= ~0x80;
127762306a36Sopenharmony_ci		}
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci	switch (protocol) {
128062306a36Sopenharmony_ci	case (-1): /* used for init */
128162306a36Sopenharmony_ci		bch->state = -1;
128262306a36Sopenharmony_ci		bch->nr = bc;
128362306a36Sopenharmony_ci		fallthrough;
128462306a36Sopenharmony_ci	case (ISDN_P_NONE):
128562306a36Sopenharmony_ci		if (bch->state == ISDN_P_NONE)
128662306a36Sopenharmony_ci			return 0;
128762306a36Sopenharmony_ci		if (bc & 2) {
128862306a36Sopenharmony_ci			hc->hw.sctrl &= ~SCTRL_B2_ENA;
128962306a36Sopenharmony_ci			hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
129062306a36Sopenharmony_ci		} else {
129162306a36Sopenharmony_ci			hc->hw.sctrl &= ~SCTRL_B1_ENA;
129262306a36Sopenharmony_ci			hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci		if (fifo2 & 2) {
129562306a36Sopenharmony_ci			hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
129662306a36Sopenharmony_ci			hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS |
129762306a36Sopenharmony_ci					   HFCPCI_INTS_B2REC);
129862306a36Sopenharmony_ci		} else {
129962306a36Sopenharmony_ci			hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
130062306a36Sopenharmony_ci			hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS |
130162306a36Sopenharmony_ci					   HFCPCI_INTS_B1REC);
130262306a36Sopenharmony_ci		}
130362306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
130462306a36Sopenharmony_ci		if (bch->nr & 2)
130562306a36Sopenharmony_ci			hc->hw.cirm &= 0x7f;
130662306a36Sopenharmony_ci		else
130762306a36Sopenharmony_ci			hc->hw.cirm &= 0xbf;
130862306a36Sopenharmony_ci#endif
130962306a36Sopenharmony_ci		bch->state = ISDN_P_NONE;
131062306a36Sopenharmony_ci		bch->nr = bc;
131162306a36Sopenharmony_ci		test_and_clear_bit(FLG_HDLC, &bch->Flags);
131262306a36Sopenharmony_ci		test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
131362306a36Sopenharmony_ci		break;
131462306a36Sopenharmony_ci	case (ISDN_P_B_RAW):
131562306a36Sopenharmony_ci		bch->state = protocol;
131662306a36Sopenharmony_ci		bch->nr = bc;
131762306a36Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
131862306a36Sopenharmony_ci		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
131962306a36Sopenharmony_ci		if (bc & 2) {
132062306a36Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B2_ENA;
132162306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
132262306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
132362306a36Sopenharmony_ci			hc->hw.cirm |= 0x80;
132462306a36Sopenharmony_ci#endif
132562306a36Sopenharmony_ci		} else {
132662306a36Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B1_ENA;
132762306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
132862306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
132962306a36Sopenharmony_ci			hc->hw.cirm |= 0x40;
133062306a36Sopenharmony_ci#endif
133162306a36Sopenharmony_ci		}
133262306a36Sopenharmony_ci		if (fifo2 & 2) {
133362306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
133462306a36Sopenharmony_ci			if (!tics)
133562306a36Sopenharmony_ci				hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
133662306a36Sopenharmony_ci						  HFCPCI_INTS_B2REC);
133762306a36Sopenharmony_ci			hc->hw.ctmt |= 2;
133862306a36Sopenharmony_ci			hc->hw.conn &= ~0x18;
133962306a36Sopenharmony_ci		} else {
134062306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
134162306a36Sopenharmony_ci			if (!tics)
134262306a36Sopenharmony_ci				hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
134362306a36Sopenharmony_ci						  HFCPCI_INTS_B1REC);
134462306a36Sopenharmony_ci			hc->hw.ctmt |= 1;
134562306a36Sopenharmony_ci			hc->hw.conn &= ~0x03;
134662306a36Sopenharmony_ci		}
134762306a36Sopenharmony_ci		test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
134862306a36Sopenharmony_ci		break;
134962306a36Sopenharmony_ci	case (ISDN_P_B_HDLC):
135062306a36Sopenharmony_ci		bch->state = protocol;
135162306a36Sopenharmony_ci		bch->nr = bc;
135262306a36Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
135362306a36Sopenharmony_ci		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
135462306a36Sopenharmony_ci		if (bc & 2) {
135562306a36Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B2_ENA;
135662306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
135762306a36Sopenharmony_ci		} else {
135862306a36Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B1_ENA;
135962306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
136062306a36Sopenharmony_ci		}
136162306a36Sopenharmony_ci		if (fifo2 & 2) {
136262306a36Sopenharmony_ci			hc->hw.last_bfifo_cnt[1] = 0;
136362306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
136462306a36Sopenharmony_ci			hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
136562306a36Sopenharmony_ci					  HFCPCI_INTS_B2REC);
136662306a36Sopenharmony_ci			hc->hw.ctmt &= ~2;
136762306a36Sopenharmony_ci			hc->hw.conn &= ~0x18;
136862306a36Sopenharmony_ci		} else {
136962306a36Sopenharmony_ci			hc->hw.last_bfifo_cnt[0] = 0;
137062306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
137162306a36Sopenharmony_ci			hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
137262306a36Sopenharmony_ci					  HFCPCI_INTS_B1REC);
137362306a36Sopenharmony_ci			hc->hw.ctmt &= ~1;
137462306a36Sopenharmony_ci			hc->hw.conn &= ~0x03;
137562306a36Sopenharmony_ci		}
137662306a36Sopenharmony_ci		test_and_set_bit(FLG_HDLC, &bch->Flags);
137762306a36Sopenharmony_ci		break;
137862306a36Sopenharmony_ci	default:
137962306a36Sopenharmony_ci		printk(KERN_DEBUG "prot not known %x\n", protocol);
138062306a36Sopenharmony_ci		return -ENOPROTOOPT;
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
138362306a36Sopenharmony_ci		if ((protocol == ISDN_P_NONE) ||
138462306a36Sopenharmony_ci		    (protocol == -1)) {	/* init case */
138562306a36Sopenharmony_ci			rx_slot = 0;
138662306a36Sopenharmony_ci			tx_slot = 0;
138762306a36Sopenharmony_ci		} else {
138862306a36Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
138962306a36Sopenharmony_ci				rx_slot |= 0xC0;
139062306a36Sopenharmony_ci				tx_slot |= 0xC0;
139162306a36Sopenharmony_ci			} else {
139262306a36Sopenharmony_ci				rx_slot |= 0x80;
139362306a36Sopenharmony_ci				tx_slot |= 0x80;
139462306a36Sopenharmony_ci			}
139562306a36Sopenharmony_ci		}
139662306a36Sopenharmony_ci		if (bc & 2) {
139762306a36Sopenharmony_ci			hc->hw.conn &= 0xc7;
139862306a36Sopenharmony_ci			hc->hw.conn |= 0x08;
139962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n",
140062306a36Sopenharmony_ci			       __func__, tx_slot);
140162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n",
140262306a36Sopenharmony_ci			       __func__, rx_slot);
140362306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
140462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
140562306a36Sopenharmony_ci		} else {
140662306a36Sopenharmony_ci			hc->hw.conn &= 0xf8;
140762306a36Sopenharmony_ci			hc->hw.conn |= 0x01;
140862306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n",
140962306a36Sopenharmony_ci			       __func__, tx_slot);
141062306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n",
141162306a36Sopenharmony_ci			       __func__, rx_slot);
141262306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
141362306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
141762306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
141862306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
141962306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
142062306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
142162306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
142262306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
142362306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
142462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
142562306a36Sopenharmony_ci#endif
142662306a36Sopenharmony_ci	return 0;
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic int
143062306a36Sopenharmony_ciset_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
143562306a36Sopenharmony_ci		printk(KERN_DEBUG
143662306a36Sopenharmony_ci		       "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n",
143762306a36Sopenharmony_ci		       bch->state, protocol, bch->nr, chan);
143862306a36Sopenharmony_ci	if (bch->nr != chan) {
143962306a36Sopenharmony_ci		printk(KERN_DEBUG
144062306a36Sopenharmony_ci		       "HFCPCI rxtest wrong channel parameter %x/%x\n",
144162306a36Sopenharmony_ci		       bch->nr, chan);
144262306a36Sopenharmony_ci		return -EINVAL;
144362306a36Sopenharmony_ci	}
144462306a36Sopenharmony_ci	switch (protocol) {
144562306a36Sopenharmony_ci	case (ISDN_P_B_RAW):
144662306a36Sopenharmony_ci		bch->state = protocol;
144762306a36Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
144862306a36Sopenharmony_ci		if (chan & 2) {
144962306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
145062306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
145162306a36Sopenharmony_ci			if (!tics)
145262306a36Sopenharmony_ci				hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
145362306a36Sopenharmony_ci			hc->hw.ctmt |= 2;
145462306a36Sopenharmony_ci			hc->hw.conn &= ~0x18;
145562306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
145662306a36Sopenharmony_ci			hc->hw.cirm |= 0x80;
145762306a36Sopenharmony_ci#endif
145862306a36Sopenharmony_ci		} else {
145962306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
146062306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
146162306a36Sopenharmony_ci			if (!tics)
146262306a36Sopenharmony_ci				hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
146362306a36Sopenharmony_ci			hc->hw.ctmt |= 1;
146462306a36Sopenharmony_ci			hc->hw.conn &= ~0x03;
146562306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
146662306a36Sopenharmony_ci			hc->hw.cirm |= 0x40;
146762306a36Sopenharmony_ci#endif
146862306a36Sopenharmony_ci		}
146962306a36Sopenharmony_ci		break;
147062306a36Sopenharmony_ci	case (ISDN_P_B_HDLC):
147162306a36Sopenharmony_ci		bch->state = protocol;
147262306a36Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
147362306a36Sopenharmony_ci		if (chan & 2) {
147462306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
147562306a36Sopenharmony_ci			hc->hw.last_bfifo_cnt[1] = 0;
147662306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
147762306a36Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
147862306a36Sopenharmony_ci			hc->hw.ctmt &= ~2;
147962306a36Sopenharmony_ci			hc->hw.conn &= ~0x18;
148062306a36Sopenharmony_ci		} else {
148162306a36Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
148262306a36Sopenharmony_ci			hc->hw.last_bfifo_cnt[0] = 0;
148362306a36Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
148462306a36Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
148562306a36Sopenharmony_ci			hc->hw.ctmt &= ~1;
148662306a36Sopenharmony_ci			hc->hw.conn &= ~0x03;
148762306a36Sopenharmony_ci		}
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	default:
149062306a36Sopenharmony_ci		printk(KERN_DEBUG "prot not known %x\n", protocol);
149162306a36Sopenharmony_ci		return -ENOPROTOOPT;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
149462306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
149562306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
149662306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
149762306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
149862306a36Sopenharmony_ci#ifdef REVERSE_BITORDER
149962306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
150062306a36Sopenharmony_ci#endif
150162306a36Sopenharmony_ci	return 0;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic void
150562306a36Sopenharmony_cideactivate_bchannel(struct bchannel *bch)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
150862306a36Sopenharmony_ci	u_long		flags;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
151162306a36Sopenharmony_ci	mISDN_clear_bchannel(bch);
151262306a36Sopenharmony_ci	mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
151362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci/*
151762306a36Sopenharmony_ci * Layer 1 B-channel hardware access
151862306a36Sopenharmony_ci */
151962306a36Sopenharmony_cistatic int
152062306a36Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	return mISDN_ctrl_bchannel(bch, cq);
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_cistatic int
152562306a36Sopenharmony_cihfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	struct bchannel	*bch = container_of(ch, struct bchannel, ch);
152862306a36Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
152962306a36Sopenharmony_ci	int		ret = -EINVAL;
153062306a36Sopenharmony_ci	u_long		flags;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW)
153362306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg);
153462306a36Sopenharmony_ci	switch (cmd) {
153562306a36Sopenharmony_ci	case HW_TESTRX_RAW:
153662306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
153762306a36Sopenharmony_ci		ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg);
153862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
153962306a36Sopenharmony_ci		break;
154062306a36Sopenharmony_ci	case HW_TESTRX_HDLC:
154162306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
154262306a36Sopenharmony_ci		ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg);
154362306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
154462306a36Sopenharmony_ci		break;
154562306a36Sopenharmony_ci	case HW_TESTRX_OFF:
154662306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
154762306a36Sopenharmony_ci		mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
154862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
154962306a36Sopenharmony_ci		ret = 0;
155062306a36Sopenharmony_ci		break;
155162306a36Sopenharmony_ci	case CLOSE_CHANNEL:
155262306a36Sopenharmony_ci		test_and_clear_bit(FLG_OPEN, &bch->Flags);
155362306a36Sopenharmony_ci		deactivate_bchannel(bch);
155462306a36Sopenharmony_ci		ch->protocol = ISDN_P_NONE;
155562306a36Sopenharmony_ci		ch->peer = NULL;
155662306a36Sopenharmony_ci		module_put(THIS_MODULE);
155762306a36Sopenharmony_ci		ret = 0;
155862306a36Sopenharmony_ci		break;
155962306a36Sopenharmony_ci	case CONTROL_CHANNEL:
156062306a36Sopenharmony_ci		ret = channel_bctrl(bch, arg);
156162306a36Sopenharmony_ci		break;
156262306a36Sopenharmony_ci	default:
156362306a36Sopenharmony_ci		printk(KERN_WARNING "%s: unknown prim(%x)\n",
156462306a36Sopenharmony_ci		       __func__, cmd);
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci	return ret;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci/*
157062306a36Sopenharmony_ci * Layer2 -> Layer 1 Dchannel data
157162306a36Sopenharmony_ci */
157262306a36Sopenharmony_cistatic int
157362306a36Sopenharmony_cihfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
157462306a36Sopenharmony_ci{
157562306a36Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
157662306a36Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
157762306a36Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
157862306a36Sopenharmony_ci	int			ret = -EINVAL;
157962306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
158062306a36Sopenharmony_ci	unsigned int		id;
158162306a36Sopenharmony_ci	u_long			flags;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	switch (hh->prim) {
158462306a36Sopenharmony_ci	case PH_DATA_REQ:
158562306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
158662306a36Sopenharmony_ci		ret = dchannel_senddata(dch, skb);
158762306a36Sopenharmony_ci		if (ret > 0) { /* direct TX */
158862306a36Sopenharmony_ci			id = hh->id; /* skb can be freed */
158962306a36Sopenharmony_ci			hfcpci_fill_dfifo(dch->hw);
159062306a36Sopenharmony_ci			ret = 0;
159162306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
159262306a36Sopenharmony_ci			queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
159362306a36Sopenharmony_ci		} else
159462306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
159562306a36Sopenharmony_ci		return ret;
159662306a36Sopenharmony_ci	case PH_ACTIVATE_REQ:
159762306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
159862306a36Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
159962306a36Sopenharmony_ci			ret = 0;
160062306a36Sopenharmony_ci			if (test_bit(HFC_CFG_MASTER, &hc->cfg))
160162306a36Sopenharmony_ci				hc->hw.mst_m |= HFCPCI_MASTER;
160262306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
160362306a36Sopenharmony_ci			if (test_bit(FLG_ACTIVE, &dch->Flags)) {
160462306a36Sopenharmony_ci				spin_unlock_irqrestore(&hc->lock, flags);
160562306a36Sopenharmony_ci				_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
160662306a36Sopenharmony_ci					    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
160762306a36Sopenharmony_ci				break;
160862306a36Sopenharmony_ci			}
160962306a36Sopenharmony_ci			test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags);
161062306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
161162306a36Sopenharmony_ci				  HFCPCI_DO_ACTION | 1);
161262306a36Sopenharmony_ci		} else
161362306a36Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
161462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
161562306a36Sopenharmony_ci		break;
161662306a36Sopenharmony_ci	case PH_DEACTIVATE_REQ:
161762306a36Sopenharmony_ci		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
161862306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
161962306a36Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
162062306a36Sopenharmony_ci			struct sk_buff_head free_queue;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci			__skb_queue_head_init(&free_queue);
162362306a36Sopenharmony_ci			/* prepare deactivation */
162462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 0x40);
162562306a36Sopenharmony_ci			skb_queue_splice_init(&dch->squeue, &free_queue);
162662306a36Sopenharmony_ci			if (dch->tx_skb) {
162762306a36Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->tx_skb);
162862306a36Sopenharmony_ci				dch->tx_skb = NULL;
162962306a36Sopenharmony_ci			}
163062306a36Sopenharmony_ci			dch->tx_idx = 0;
163162306a36Sopenharmony_ci			if (dch->rx_skb) {
163262306a36Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->rx_skb);
163362306a36Sopenharmony_ci				dch->rx_skb = NULL;
163462306a36Sopenharmony_ci			}
163562306a36Sopenharmony_ci			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
163662306a36Sopenharmony_ci			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
163762306a36Sopenharmony_ci				del_timer(&dch->timer);
163862306a36Sopenharmony_ci#ifdef FIXME
163962306a36Sopenharmony_ci			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
164062306a36Sopenharmony_ci				dchannel_sched_event(&hc->dch, D_CLEARBUSY);
164162306a36Sopenharmony_ci#endif
164262306a36Sopenharmony_ci			hc->hw.mst_m &= ~HFCPCI_MASTER;
164362306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
164462306a36Sopenharmony_ci			ret = 0;
164562306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
164662306a36Sopenharmony_ci			__skb_queue_purge(&free_queue);
164762306a36Sopenharmony_ci		} else {
164862306a36Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
164962306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci		break;
165262306a36Sopenharmony_ci	}
165362306a36Sopenharmony_ci	if (!ret)
165462306a36Sopenharmony_ci		dev_kfree_skb(skb);
165562306a36Sopenharmony_ci	return ret;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci/*
165962306a36Sopenharmony_ci * Layer2 -> Layer 1 Bchannel data
166062306a36Sopenharmony_ci */
166162306a36Sopenharmony_cistatic int
166262306a36Sopenharmony_cihfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	struct bchannel		*bch = container_of(ch, struct bchannel, ch);
166562306a36Sopenharmony_ci	struct hfc_pci		*hc = bch->hw;
166662306a36Sopenharmony_ci	int			ret = -EINVAL;
166762306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
166862306a36Sopenharmony_ci	unsigned long		flags;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	switch (hh->prim) {
167162306a36Sopenharmony_ci	case PH_DATA_REQ:
167262306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
167362306a36Sopenharmony_ci		ret = bchannel_senddata(bch, skb);
167462306a36Sopenharmony_ci		if (ret > 0) { /* direct TX */
167562306a36Sopenharmony_ci			hfcpci_fill_fifo(bch);
167662306a36Sopenharmony_ci			ret = 0;
167762306a36Sopenharmony_ci		}
167862306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
167962306a36Sopenharmony_ci		return ret;
168062306a36Sopenharmony_ci	case PH_ACTIVATE_REQ:
168162306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
168262306a36Sopenharmony_ci		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
168362306a36Sopenharmony_ci			ret = mode_hfcpci(bch, bch->nr, ch->protocol);
168462306a36Sopenharmony_ci		else
168562306a36Sopenharmony_ci			ret = 0;
168662306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
168762306a36Sopenharmony_ci		if (!ret)
168862306a36Sopenharmony_ci			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
168962306a36Sopenharmony_ci				    NULL, GFP_KERNEL);
169062306a36Sopenharmony_ci		break;
169162306a36Sopenharmony_ci	case PH_DEACTIVATE_REQ:
169262306a36Sopenharmony_ci		deactivate_bchannel(bch);
169362306a36Sopenharmony_ci		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
169462306a36Sopenharmony_ci			    NULL, GFP_KERNEL);
169562306a36Sopenharmony_ci		ret = 0;
169662306a36Sopenharmony_ci		break;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci	if (!ret)
169962306a36Sopenharmony_ci		dev_kfree_skb(skb);
170062306a36Sopenharmony_ci	return ret;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci/*
170462306a36Sopenharmony_ci * called for card init message
170562306a36Sopenharmony_ci */
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic void
170862306a36Sopenharmony_ciinithfcpci(struct hfc_pci *hc)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	printk(KERN_DEBUG "inithfcpci: entered\n");
171162306a36Sopenharmony_ci	timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0);
171262306a36Sopenharmony_ci	hc->chanlimit = 2;
171362306a36Sopenharmony_ci	mode_hfcpci(&hc->bch[0], 1, -1);
171462306a36Sopenharmony_ci	mode_hfcpci(&hc->bch[1], 2, -1);
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistatic int
171962306a36Sopenharmony_ciinit_card(struct hfc_pci *hc)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	int	cnt = 3;
172262306a36Sopenharmony_ci	u_long	flags;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	printk(KERN_DEBUG "init_card: entered\n");
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
172862306a36Sopenharmony_ci	disable_hwirq(hc);
172962306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
173062306a36Sopenharmony_ci	if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) {
173162306a36Sopenharmony_ci		printk(KERN_WARNING
173262306a36Sopenharmony_ci		       "mISDN: couldn't get interrupt %d\n", hc->irq);
173362306a36Sopenharmony_ci		return -EIO;
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
173662306a36Sopenharmony_ci	reset_hfcpci(hc);
173762306a36Sopenharmony_ci	while (cnt) {
173862306a36Sopenharmony_ci		inithfcpci(hc);
173962306a36Sopenharmony_ci		/*
174062306a36Sopenharmony_ci		 * Finally enable IRQ output
174162306a36Sopenharmony_ci		 * this is only allowed, if an IRQ routine is already
174262306a36Sopenharmony_ci		 * established for this HFC, so don't do that earlier
174362306a36Sopenharmony_ci		 */
174462306a36Sopenharmony_ci		enable_hwirq(hc);
174562306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
174662306a36Sopenharmony_ci		/* Timeout 80ms */
174762306a36Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
174862306a36Sopenharmony_ci		schedule_timeout((80 * HZ) / 1000);
174962306a36Sopenharmony_ci		printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
175062306a36Sopenharmony_ci		       hc->irq, hc->irqcnt);
175162306a36Sopenharmony_ci		/* now switch timer interrupt off */
175262306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
175362306a36Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
175462306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
175562306a36Sopenharmony_ci		/* reinit mode reg */
175662306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
175762306a36Sopenharmony_ci		if (!hc->irqcnt) {
175862306a36Sopenharmony_ci			printk(KERN_WARNING
175962306a36Sopenharmony_ci			       "HFC PCI: IRQ(%d) getting no interrupts "
176062306a36Sopenharmony_ci			       "during init %d\n", hc->irq, 4 - cnt);
176162306a36Sopenharmony_ci			if (cnt == 1)
176262306a36Sopenharmony_ci				break;
176362306a36Sopenharmony_ci			else {
176462306a36Sopenharmony_ci				reset_hfcpci(hc);
176562306a36Sopenharmony_ci				cnt--;
176662306a36Sopenharmony_ci			}
176762306a36Sopenharmony_ci		} else {
176862306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
176962306a36Sopenharmony_ci			hc->initdone = 1;
177062306a36Sopenharmony_ci			return 0;
177162306a36Sopenharmony_ci		}
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci	disable_hwirq(hc);
177462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
177562306a36Sopenharmony_ci	free_irq(hc->irq, hc);
177662306a36Sopenharmony_ci	return -EIO;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic int
178062306a36Sopenharmony_cichannel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq)
178162306a36Sopenharmony_ci{
178262306a36Sopenharmony_ci	int	ret = 0;
178362306a36Sopenharmony_ci	u_char	slot;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	switch (cq->op) {
178662306a36Sopenharmony_ci	case MISDN_CTRL_GETOP:
178762306a36Sopenharmony_ci		cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
178862306a36Sopenharmony_ci			 MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3;
178962306a36Sopenharmony_ci		break;
179062306a36Sopenharmony_ci	case MISDN_CTRL_LOOP:
179162306a36Sopenharmony_ci		/* channel 0 disabled loop */
179262306a36Sopenharmony_ci		if (cq->channel < 0 || cq->channel > 2) {
179362306a36Sopenharmony_ci			ret = -EINVAL;
179462306a36Sopenharmony_ci			break;
179562306a36Sopenharmony_ci		}
179662306a36Sopenharmony_ci		if (cq->channel & 1) {
179762306a36Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
179862306a36Sopenharmony_ci				slot = 0xC0;
179962306a36Sopenharmony_ci			else
180062306a36Sopenharmony_ci				slot = 0x80;
180162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
180262306a36Sopenharmony_ci			       __func__, slot);
180362306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, slot);
180462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, slot);
180562306a36Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~7) | 6;
180662306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
180762306a36Sopenharmony_ci		}
180862306a36Sopenharmony_ci		if (cq->channel & 2) {
180962306a36Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
181062306a36Sopenharmony_ci				slot = 0xC1;
181162306a36Sopenharmony_ci			else
181262306a36Sopenharmony_ci				slot = 0x81;
181362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
181462306a36Sopenharmony_ci			       __func__, slot);
181562306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, slot);
181662306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, slot);
181762306a36Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30;
181862306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
181962306a36Sopenharmony_ci		}
182062306a36Sopenharmony_ci		if (cq->channel & 3)
182162306a36Sopenharmony_ci			hc->hw.trm |= 0x80;	/* enable IOM-loop */
182262306a36Sopenharmony_ci		else {
182362306a36Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
182462306a36Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
182562306a36Sopenharmony_ci			hc->hw.trm &= 0x7f;	/* disable IOM-loop */
182662306a36Sopenharmony_ci		}
182762306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
182862306a36Sopenharmony_ci		break;
182962306a36Sopenharmony_ci	case MISDN_CTRL_CONNECT:
183062306a36Sopenharmony_ci		if (cq->channel == cq->p1) {
183162306a36Sopenharmony_ci			ret = -EINVAL;
183262306a36Sopenharmony_ci			break;
183362306a36Sopenharmony_ci		}
183462306a36Sopenharmony_ci		if (cq->channel < 1 || cq->channel > 2 ||
183562306a36Sopenharmony_ci		    cq->p1 < 1 || cq->p1 > 2) {
183662306a36Sopenharmony_ci			ret = -EINVAL;
183762306a36Sopenharmony_ci			break;
183862306a36Sopenharmony_ci		}
183962306a36Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
184062306a36Sopenharmony_ci			slot = 0xC0;
184162306a36Sopenharmony_ci		else
184262306a36Sopenharmony_ci			slot = 0x80;
184362306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
184462306a36Sopenharmony_ci		       __func__, slot);
184562306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_B1_SSL, slot);
184662306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_B2_RSL, slot);
184762306a36Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
184862306a36Sopenharmony_ci			slot = 0xC1;
184962306a36Sopenharmony_ci		else
185062306a36Sopenharmony_ci			slot = 0x81;
185162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
185262306a36Sopenharmony_ci		       __func__, slot);
185362306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_B2_SSL, slot);
185462306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_B1_RSL, slot);
185562306a36Sopenharmony_ci		hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36;
185662306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
185762306a36Sopenharmony_ci		hc->hw.trm |= 0x80;
185862306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
185962306a36Sopenharmony_ci		break;
186062306a36Sopenharmony_ci	case MISDN_CTRL_DISCONNECT:
186162306a36Sopenharmony_ci		hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
186262306a36Sopenharmony_ci		Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
186362306a36Sopenharmony_ci		hc->hw.trm &= 0x7f;	/* disable IOM-loop */
186462306a36Sopenharmony_ci		break;
186562306a36Sopenharmony_ci	case MISDN_CTRL_L1_TIMER3:
186662306a36Sopenharmony_ci		ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
186762306a36Sopenharmony_ci		break;
186862306a36Sopenharmony_ci	default:
186962306a36Sopenharmony_ci		printk(KERN_WARNING "%s: unknown Op %x\n",
187062306a36Sopenharmony_ci		       __func__, cq->op);
187162306a36Sopenharmony_ci		ret = -EINVAL;
187262306a36Sopenharmony_ci		break;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci	return ret;
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_cistatic int
187862306a36Sopenharmony_ciopen_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch,
187962306a36Sopenharmony_ci	      struct channel_req *rq)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	int err = 0;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	if (debug & DEBUG_HW_OPEN)
188462306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
188562306a36Sopenharmony_ci		       hc->dch.dev.id, __builtin_return_address(0));
188662306a36Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
188762306a36Sopenharmony_ci		return -EINVAL;
188862306a36Sopenharmony_ci	if (rq->adr.channel == 1) {
188962306a36Sopenharmony_ci		/* TODO: E-Channel */
189062306a36Sopenharmony_ci		return -EINVAL;
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci	if (!hc->initdone) {
189362306a36Sopenharmony_ci		if (rq->protocol == ISDN_P_TE_S0) {
189462306a36Sopenharmony_ci			err = create_l1(&hc->dch, hfc_l1callback);
189562306a36Sopenharmony_ci			if (err)
189662306a36Sopenharmony_ci				return err;
189762306a36Sopenharmony_ci		}
189862306a36Sopenharmony_ci		hc->hw.protocol = rq->protocol;
189962306a36Sopenharmony_ci		ch->protocol = rq->protocol;
190062306a36Sopenharmony_ci		err = init_card(hc);
190162306a36Sopenharmony_ci		if (err)
190262306a36Sopenharmony_ci			return err;
190362306a36Sopenharmony_ci	} else {
190462306a36Sopenharmony_ci		if (rq->protocol != ch->protocol) {
190562306a36Sopenharmony_ci			if (hc->hw.protocol == ISDN_P_TE_S0)
190662306a36Sopenharmony_ci				l1_event(hc->dch.l1, CLOSE_CHANNEL);
190762306a36Sopenharmony_ci			if (rq->protocol == ISDN_P_TE_S0) {
190862306a36Sopenharmony_ci				err = create_l1(&hc->dch, hfc_l1callback);
190962306a36Sopenharmony_ci				if (err)
191062306a36Sopenharmony_ci					return err;
191162306a36Sopenharmony_ci			}
191262306a36Sopenharmony_ci			hc->hw.protocol = rq->protocol;
191362306a36Sopenharmony_ci			ch->protocol = rq->protocol;
191462306a36Sopenharmony_ci			hfcpci_setmode(hc);
191562306a36Sopenharmony_ci		}
191662306a36Sopenharmony_ci	}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) ||
191962306a36Sopenharmony_ci	    ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) {
192062306a36Sopenharmony_ci		_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
192162306a36Sopenharmony_ci			    0, NULL, GFP_KERNEL);
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci	rq->ch = ch;
192462306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
192562306a36Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
192662306a36Sopenharmony_ci	return 0;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic int
193062306a36Sopenharmony_ciopen_bchannel(struct hfc_pci *hc, struct channel_req *rq)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	struct bchannel		*bch;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if (rq->adr.channel == 0 || rq->adr.channel > 2)
193562306a36Sopenharmony_ci		return -EINVAL;
193662306a36Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
193762306a36Sopenharmony_ci		return -EINVAL;
193862306a36Sopenharmony_ci	bch = &hc->bch[rq->adr.channel - 1];
193962306a36Sopenharmony_ci	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
194062306a36Sopenharmony_ci		return -EBUSY; /* b-channel can be only open once */
194162306a36Sopenharmony_ci	bch->ch.protocol = rq->protocol;
194262306a36Sopenharmony_ci	rq->ch = &bch->ch; /* TODO: E-channel */
194362306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
194462306a36Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
194562306a36Sopenharmony_ci	return 0;
194662306a36Sopenharmony_ci}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci/*
194962306a36Sopenharmony_ci * device control function
195062306a36Sopenharmony_ci */
195162306a36Sopenharmony_cistatic int
195262306a36Sopenharmony_cihfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
195362306a36Sopenharmony_ci{
195462306a36Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
195562306a36Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
195662306a36Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
195762306a36Sopenharmony_ci	struct channel_req	*rq;
195862306a36Sopenharmony_ci	int			err = 0;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	if (dch->debug & DEBUG_HW)
196162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n",
196262306a36Sopenharmony_ci		       __func__, cmd, arg);
196362306a36Sopenharmony_ci	switch (cmd) {
196462306a36Sopenharmony_ci	case OPEN_CHANNEL:
196562306a36Sopenharmony_ci		rq = arg;
196662306a36Sopenharmony_ci		if ((rq->protocol == ISDN_P_TE_S0) ||
196762306a36Sopenharmony_ci		    (rq->protocol == ISDN_P_NT_S0))
196862306a36Sopenharmony_ci			err = open_dchannel(hc, ch, rq);
196962306a36Sopenharmony_ci		else
197062306a36Sopenharmony_ci			err = open_bchannel(hc, rq);
197162306a36Sopenharmony_ci		break;
197262306a36Sopenharmony_ci	case CLOSE_CHANNEL:
197362306a36Sopenharmony_ci		if (debug & DEBUG_HW_OPEN)
197462306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
197562306a36Sopenharmony_ci			       __func__, hc->dch.dev.id,
197662306a36Sopenharmony_ci			       __builtin_return_address(0));
197762306a36Sopenharmony_ci		module_put(THIS_MODULE);
197862306a36Sopenharmony_ci		break;
197962306a36Sopenharmony_ci	case CONTROL_CHANNEL:
198062306a36Sopenharmony_ci		err = channel_ctrl(hc, arg);
198162306a36Sopenharmony_ci		break;
198262306a36Sopenharmony_ci	default:
198362306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW)
198462306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
198562306a36Sopenharmony_ci			       __func__, cmd);
198662306a36Sopenharmony_ci		return -EINVAL;
198762306a36Sopenharmony_ci	}
198862306a36Sopenharmony_ci	return err;
198962306a36Sopenharmony_ci}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_cistatic int
199262306a36Sopenharmony_cisetup_hw(struct hfc_pci *hc)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	void	*buffer;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision);
199762306a36Sopenharmony_ci	hc->hw.cirm = 0;
199862306a36Sopenharmony_ci	hc->dch.state = 0;
199962306a36Sopenharmony_ci	pci_set_master(hc->pdev);
200062306a36Sopenharmony_ci	if (!hc->irq) {
200162306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
200262306a36Sopenharmony_ci		return -EINVAL;
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci	hc->hw.pci_io =
200562306a36Sopenharmony_ci		(char __iomem *)(unsigned long)hc->pdev->resource[1].start;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	if (!hc->hw.pci_io) {
200862306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
200962306a36Sopenharmony_ci		return -ENOMEM;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci	/* Allocate memory for FIFOS */
201262306a36Sopenharmony_ci	/* the memory needs to be on a 32k boundary within the first 4G */
201362306a36Sopenharmony_ci	if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) {
201462306a36Sopenharmony_ci		printk(KERN_WARNING
201562306a36Sopenharmony_ci		       "HFC-PCI: No usable DMA configuration!\n");
201662306a36Sopenharmony_ci		return -EIO;
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci	buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle,
201962306a36Sopenharmony_ci				    GFP_KERNEL);
202062306a36Sopenharmony_ci	/* We silently assume the address is okay if nonzero */
202162306a36Sopenharmony_ci	if (!buffer) {
202262306a36Sopenharmony_ci		printk(KERN_WARNING
202362306a36Sopenharmony_ci		       "HFC-PCI: Error allocating memory for FIFO!\n");
202462306a36Sopenharmony_ci		return -ENOMEM;
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci	hc->hw.fifos = buffer;
202762306a36Sopenharmony_ci	pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle);
202862306a36Sopenharmony_ci	hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256);
202962306a36Sopenharmony_ci	if (unlikely(!hc->hw.pci_io)) {
203062306a36Sopenharmony_ci		printk(KERN_WARNING
203162306a36Sopenharmony_ci		       "HFC-PCI: Error in ioremap for PCI!\n");
203262306a36Sopenharmony_ci		dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
203362306a36Sopenharmony_ci				  hc->hw.dmahandle);
203462306a36Sopenharmony_ci		return -ENOMEM;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	printk(KERN_INFO
203862306a36Sopenharmony_ci	       "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n",
203962306a36Sopenharmony_ci	       (u_long) hc->hw.pci_io, hc->hw.fifos,
204062306a36Sopenharmony_ci	       &hc->hw.dmahandle, hc->irq, HZ);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	/* enable memory mapped ports, disable busmaster */
204362306a36Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
204462306a36Sopenharmony_ci	hc->hw.int_m2 = 0;
204562306a36Sopenharmony_ci	disable_hwirq(hc);
204662306a36Sopenharmony_ci	hc->hw.int_m1 = 0;
204762306a36Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
204862306a36Sopenharmony_ci	/* At this point the needed PCI config is done */
204962306a36Sopenharmony_ci	/* fifos are still not enabled */
205062306a36Sopenharmony_ci	timer_setup(&hc->hw.timer, hfcpci_Timer, 0);
205162306a36Sopenharmony_ci	/* default PCM master */
205262306a36Sopenharmony_ci	test_and_set_bit(HFC_CFG_MASTER, &hc->cfg);
205362306a36Sopenharmony_ci	return 0;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic void
205762306a36Sopenharmony_cirelease_card(struct hfc_pci *hc) {
205862306a36Sopenharmony_ci	u_long	flags;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
206162306a36Sopenharmony_ci	hc->hw.int_m2 = 0; /* interrupt output off ! */
206262306a36Sopenharmony_ci	disable_hwirq(hc);
206362306a36Sopenharmony_ci	mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE);
206462306a36Sopenharmony_ci	mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE);
206562306a36Sopenharmony_ci	if (hc->dch.timer.function != NULL) {
206662306a36Sopenharmony_ci		del_timer(&hc->dch.timer);
206762306a36Sopenharmony_ci		hc->dch.timer.function = NULL;
206862306a36Sopenharmony_ci	}
206962306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
207062306a36Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_TE_S0)
207162306a36Sopenharmony_ci		l1_event(hc->dch.l1, CLOSE_CHANNEL);
207262306a36Sopenharmony_ci	if (hc->initdone)
207362306a36Sopenharmony_ci		free_irq(hc->irq, hc);
207462306a36Sopenharmony_ci	release_io_hfcpci(hc); /* must release after free_irq! */
207562306a36Sopenharmony_ci	mISDN_unregister_device(&hc->dch.dev);
207662306a36Sopenharmony_ci	mISDN_freebchannel(&hc->bch[1]);
207762306a36Sopenharmony_ci	mISDN_freebchannel(&hc->bch[0]);
207862306a36Sopenharmony_ci	mISDN_freedchannel(&hc->dch);
207962306a36Sopenharmony_ci	pci_set_drvdata(hc->pdev, NULL);
208062306a36Sopenharmony_ci	kfree(hc);
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic int
208462306a36Sopenharmony_cisetup_card(struct hfc_pci *card)
208562306a36Sopenharmony_ci{
208662306a36Sopenharmony_ci	int		err = -EINVAL;
208762306a36Sopenharmony_ci	u_int		i;
208862306a36Sopenharmony_ci	char		name[MISDN_MAX_IDLEN];
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	card->dch.debug = debug;
209162306a36Sopenharmony_ci	spin_lock_init(&card->lock);
209262306a36Sopenharmony_ci	mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state);
209362306a36Sopenharmony_ci	card->dch.hw = card;
209462306a36Sopenharmony_ci	card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
209562306a36Sopenharmony_ci	card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
209662306a36Sopenharmony_ci		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
209762306a36Sopenharmony_ci	card->dch.dev.D.send = hfcpci_l2l1D;
209862306a36Sopenharmony_ci	card->dch.dev.D.ctrl = hfc_dctrl;
209962306a36Sopenharmony_ci	card->dch.dev.nrbchan = 2;
210062306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
210162306a36Sopenharmony_ci		card->bch[i].nr = i + 1;
210262306a36Sopenharmony_ci		set_channelmap(i + 1, card->dch.dev.channelmap);
210362306a36Sopenharmony_ci		card->bch[i].debug = debug;
210462306a36Sopenharmony_ci		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1);
210562306a36Sopenharmony_ci		card->bch[i].hw = card;
210662306a36Sopenharmony_ci		card->bch[i].ch.send = hfcpci_l2l1B;
210762306a36Sopenharmony_ci		card->bch[i].ch.ctrl = hfc_bctrl;
210862306a36Sopenharmony_ci		card->bch[i].ch.nr = i + 1;
210962306a36Sopenharmony_ci		list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels);
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci	err = setup_hw(card);
211262306a36Sopenharmony_ci	if (err)
211362306a36Sopenharmony_ci		goto error;
211462306a36Sopenharmony_ci	snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1);
211562306a36Sopenharmony_ci	err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name);
211662306a36Sopenharmony_ci	if (err)
211762306a36Sopenharmony_ci		goto error;
211862306a36Sopenharmony_ci	HFC_cnt++;
211962306a36Sopenharmony_ci	printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
212062306a36Sopenharmony_ci	return 0;
212162306a36Sopenharmony_cierror:
212262306a36Sopenharmony_ci	mISDN_freebchannel(&card->bch[1]);
212362306a36Sopenharmony_ci	mISDN_freebchannel(&card->bch[0]);
212462306a36Sopenharmony_ci	mISDN_freedchannel(&card->dch);
212562306a36Sopenharmony_ci	kfree(card);
212662306a36Sopenharmony_ci	return err;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci/* private data in the PCI devices list */
213062306a36Sopenharmony_cistruct _hfc_map {
213162306a36Sopenharmony_ci	u_int	subtype;
213262306a36Sopenharmony_ci	u_int	flag;
213362306a36Sopenharmony_ci	char	*name;
213462306a36Sopenharmony_ci};
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic const struct _hfc_map hfc_map[] =
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	{HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"},
213962306a36Sopenharmony_ci	{HFC_CCD_B000, 0, "Billion B000"},
214062306a36Sopenharmony_ci	{HFC_CCD_B006, 0, "Billion B006"},
214162306a36Sopenharmony_ci	{HFC_CCD_B007, 0, "Billion B007"},
214262306a36Sopenharmony_ci	{HFC_CCD_B008, 0, "Billion B008"},
214362306a36Sopenharmony_ci	{HFC_CCD_B009, 0, "Billion B009"},
214462306a36Sopenharmony_ci	{HFC_CCD_B00A, 0, "Billion B00A"},
214562306a36Sopenharmony_ci	{HFC_CCD_B00B, 0, "Billion B00B"},
214662306a36Sopenharmony_ci	{HFC_CCD_B00C, 0, "Billion B00C"},
214762306a36Sopenharmony_ci	{HFC_CCD_B100, 0, "Seyeon B100"},
214862306a36Sopenharmony_ci	{HFC_CCD_B700, 0, "Primux II S0 B700"},
214962306a36Sopenharmony_ci	{HFC_CCD_B701, 0, "Primux II S0 NT B701"},
215062306a36Sopenharmony_ci	{HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"},
215162306a36Sopenharmony_ci	{HFC_ASUS_0675, 0, "Asuscom/Askey 675"},
215262306a36Sopenharmony_ci	{HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"},
215362306a36Sopenharmony_ci	{HFC_BERKOM_A1T, 0, "German telekom A1T"},
215462306a36Sopenharmony_ci	{HFC_ANIGMA_MC145575, 0, "Motorola MC145575"},
215562306a36Sopenharmony_ci	{HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"},
215662306a36Sopenharmony_ci	{HFC_DIGI_DF_M_IOM2_E, 0,
215762306a36Sopenharmony_ci	 "Digi International DataFire Micro V IOM2 (Europe)"},
215862306a36Sopenharmony_ci	{HFC_DIGI_DF_M_E, 0,
215962306a36Sopenharmony_ci	 "Digi International DataFire Micro V (Europe)"},
216062306a36Sopenharmony_ci	{HFC_DIGI_DF_M_IOM2_A, 0,
216162306a36Sopenharmony_ci	 "Digi International DataFire Micro V IOM2 (North America)"},
216262306a36Sopenharmony_ci	{HFC_DIGI_DF_M_A, 0,
216362306a36Sopenharmony_ci	 "Digi International DataFire Micro V (North America)"},
216462306a36Sopenharmony_ci	{HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"},
216562306a36Sopenharmony_ci	{},
216662306a36Sopenharmony_ci};
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic const struct pci_device_id hfc_ids[] =
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
217162306a36Sopenharmony_ci	  (unsigned long) &hfc_map[0] },
217262306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000),
217362306a36Sopenharmony_ci	  (unsigned long) &hfc_map[1] },
217462306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006),
217562306a36Sopenharmony_ci	  (unsigned long) &hfc_map[2] },
217662306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007),
217762306a36Sopenharmony_ci	  (unsigned long) &hfc_map[3] },
217862306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008),
217962306a36Sopenharmony_ci	  (unsigned long) &hfc_map[4] },
218062306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009),
218162306a36Sopenharmony_ci	  (unsigned long) &hfc_map[5] },
218262306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A),
218362306a36Sopenharmony_ci	  (unsigned long) &hfc_map[6] },
218462306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B),
218562306a36Sopenharmony_ci	  (unsigned long) &hfc_map[7] },
218662306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C),
218762306a36Sopenharmony_ci	  (unsigned long) &hfc_map[8] },
218862306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100),
218962306a36Sopenharmony_ci	  (unsigned long) &hfc_map[9] },
219062306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700),
219162306a36Sopenharmony_ci	  (unsigned long) &hfc_map[10] },
219262306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701),
219362306a36Sopenharmony_ci	  (unsigned long) &hfc_map[11] },
219462306a36Sopenharmony_ci	{ PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1),
219562306a36Sopenharmony_ci	  (unsigned long) &hfc_map[12] },
219662306a36Sopenharmony_ci	{ PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675),
219762306a36Sopenharmony_ci	  (unsigned long) &hfc_map[13] },
219862306a36Sopenharmony_ci	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT),
219962306a36Sopenharmony_ci	  (unsigned long) &hfc_map[14] },
220062306a36Sopenharmony_ci	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T),
220162306a36Sopenharmony_ci	  (unsigned long) &hfc_map[15] },
220262306a36Sopenharmony_ci	{ PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575),
220362306a36Sopenharmony_ci	  (unsigned long) &hfc_map[16] },
220462306a36Sopenharmony_ci	{ PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0),
220562306a36Sopenharmony_ci	  (unsigned long) &hfc_map[17] },
220662306a36Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E),
220762306a36Sopenharmony_ci	  (unsigned long) &hfc_map[18] },
220862306a36Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E),
220962306a36Sopenharmony_ci	  (unsigned long) &hfc_map[19] },
221062306a36Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A),
221162306a36Sopenharmony_ci	  (unsigned long) &hfc_map[20] },
221262306a36Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A),
221362306a36Sopenharmony_ci	  (unsigned long) &hfc_map[21] },
221462306a36Sopenharmony_ci	{ PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2),
221562306a36Sopenharmony_ci	  (unsigned long) &hfc_map[22] },
221662306a36Sopenharmony_ci	{},
221762306a36Sopenharmony_ci};
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_cistatic int
222062306a36Sopenharmony_cihfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
222162306a36Sopenharmony_ci{
222262306a36Sopenharmony_ci	int		err = -ENOMEM;
222362306a36Sopenharmony_ci	struct hfc_pci	*card;
222462306a36Sopenharmony_ci	struct _hfc_map	*m = (struct _hfc_map *)ent->driver_data;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	card = kzalloc(sizeof(struct hfc_pci), GFP_KERNEL);
222762306a36Sopenharmony_ci	if (!card) {
222862306a36Sopenharmony_ci		printk(KERN_ERR "No kmem for HFC card\n");
222962306a36Sopenharmony_ci		return err;
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci	card->pdev = pdev;
223262306a36Sopenharmony_ci	card->subtype = m->subtype;
223362306a36Sopenharmony_ci	err = pci_enable_device(pdev);
223462306a36Sopenharmony_ci	if (err) {
223562306a36Sopenharmony_ci		kfree(card);
223662306a36Sopenharmony_ci		return err;
223762306a36Sopenharmony_ci	}
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n",
224062306a36Sopenharmony_ci	       m->name, pci_name(pdev));
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	card->irq = pdev->irq;
224362306a36Sopenharmony_ci	pci_set_drvdata(pdev, card);
224462306a36Sopenharmony_ci	err = setup_card(card);
224562306a36Sopenharmony_ci	if (err)
224662306a36Sopenharmony_ci		pci_set_drvdata(pdev, NULL);
224762306a36Sopenharmony_ci	return err;
224862306a36Sopenharmony_ci}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_cistatic void
225162306a36Sopenharmony_cihfc_remove_pci(struct pci_dev *pdev)
225262306a36Sopenharmony_ci{
225362306a36Sopenharmony_ci	struct hfc_pci	*card = pci_get_drvdata(pdev);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (card)
225662306a36Sopenharmony_ci		release_card(card);
225762306a36Sopenharmony_ci	else
225862306a36Sopenharmony_ci		if (debug)
225962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: drvdata already removed\n",
226062306a36Sopenharmony_ci			       __func__);
226162306a36Sopenharmony_ci}
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_cistatic struct pci_driver hfc_driver = {
226562306a36Sopenharmony_ci	.name = "hfcpci",
226662306a36Sopenharmony_ci	.probe = hfc_probe,
226762306a36Sopenharmony_ci	.remove = hfc_remove_pci,
226862306a36Sopenharmony_ci	.id_table = hfc_ids,
226962306a36Sopenharmony_ci};
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_cistatic int
227262306a36Sopenharmony_ci_hfcpci_softirq(struct device *dev, void *unused)
227362306a36Sopenharmony_ci{
227462306a36Sopenharmony_ci	struct hfc_pci  *hc = dev_get_drvdata(dev);
227562306a36Sopenharmony_ci	struct bchannel *bch;
227662306a36Sopenharmony_ci	if (hc == NULL)
227762306a36Sopenharmony_ci		return 0;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
228062306a36Sopenharmony_ci		spin_lock_irq(&hc->lock);
228162306a36Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
228262306a36Sopenharmony_ci		if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
228362306a36Sopenharmony_ci			main_rec_hfcpci(bch);
228462306a36Sopenharmony_ci			tx_birq(bch);
228562306a36Sopenharmony_ci		}
228662306a36Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2);
228762306a36Sopenharmony_ci		if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */
228862306a36Sopenharmony_ci			main_rec_hfcpci(bch);
228962306a36Sopenharmony_ci			tx_birq(bch);
229062306a36Sopenharmony_ci		}
229162306a36Sopenharmony_ci		spin_unlock_irq(&hc->lock);
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci	return 0;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_cistatic void
229762306a36Sopenharmony_cihfcpci_softirq(struct timer_list *unused)
229862306a36Sopenharmony_ci{
229962306a36Sopenharmony_ci	WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL,
230062306a36Sopenharmony_ci				      _hfcpci_softirq) != 0);
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	/* if next event would be in the past ... */
230362306a36Sopenharmony_ci	if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
230462306a36Sopenharmony_ci		hfc_jiffies = jiffies + 1;
230562306a36Sopenharmony_ci	else
230662306a36Sopenharmony_ci		hfc_jiffies += tics;
230762306a36Sopenharmony_ci	hfc_tl.expires = hfc_jiffies;
230862306a36Sopenharmony_ci	add_timer(&hfc_tl);
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_cistatic int __init
231262306a36Sopenharmony_ciHFC_init(void)
231362306a36Sopenharmony_ci{
231462306a36Sopenharmony_ci	int		err;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	if (!poll)
231762306a36Sopenharmony_ci		poll = HFCPCI_BTRANS_THRESHOLD;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (poll != HFCPCI_BTRANS_THRESHOLD) {
232062306a36Sopenharmony_ci		tics = (poll * HZ) / 8000;
232162306a36Sopenharmony_ci		if (tics < 1)
232262306a36Sopenharmony_ci			tics = 1;
232362306a36Sopenharmony_ci		poll = (tics * 8000) / HZ;
232462306a36Sopenharmony_ci		if (poll > 256 || poll < 8) {
232562306a36Sopenharmony_ci			printk(KERN_ERR "%s: Wrong poll value %d not in range "
232662306a36Sopenharmony_ci			       "of 8..256.\n", __func__, poll);
232762306a36Sopenharmony_ci			err = -EINVAL;
232862306a36Sopenharmony_ci			return err;
232962306a36Sopenharmony_ci		}
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci	if (poll != HFCPCI_BTRANS_THRESHOLD) {
233262306a36Sopenharmony_ci		printk(KERN_INFO "%s: Using alternative poll value of %d\n",
233362306a36Sopenharmony_ci		       __func__, poll);
233462306a36Sopenharmony_ci		timer_setup(&hfc_tl, hfcpci_softirq, 0);
233562306a36Sopenharmony_ci		hfc_tl.expires = jiffies + tics;
233662306a36Sopenharmony_ci		hfc_jiffies = hfc_tl.expires;
233762306a36Sopenharmony_ci		add_timer(&hfc_tl);
233862306a36Sopenharmony_ci	} else
233962306a36Sopenharmony_ci		tics = 0; /* indicate the use of controller's timer */
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	err = pci_register_driver(&hfc_driver);
234262306a36Sopenharmony_ci	if (err) {
234362306a36Sopenharmony_ci		if (timer_pending(&hfc_tl))
234462306a36Sopenharmony_ci			del_timer(&hfc_tl);
234562306a36Sopenharmony_ci	}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return err;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_cistatic void __exit
235162306a36Sopenharmony_ciHFC_cleanup(void)
235262306a36Sopenharmony_ci{
235362306a36Sopenharmony_ci	del_timer_sync(&hfc_tl);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	pci_unregister_driver(&hfc_driver);
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cimodule_init(HFC_init);
235962306a36Sopenharmony_cimodule_exit(HFC_cleanup);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfc_ids);
2362