18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * hfcpci.c     low level driver for CCD's hfc-pci based cards
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Author     Werner Cornelius (werner@isdn4linux.de)
78c2ecf20Sopenharmony_ci *            based on existing driver for CCD hfc ISA cards
88c2ecf20Sopenharmony_ci *            type approval valid for HFC-S PCI A based card
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright 1999  by Werner Cornelius (werner@isdn-development.de)
118c2ecf20Sopenharmony_ci * Copyright 2008  by Karsten Keil <kkeil@novell.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Module options:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * debug:
168c2ecf20Sopenharmony_ci *	NOTE: only one poll value must be given for all cards
178c2ecf20Sopenharmony_ci *	See hfc_pci.h for debug flags.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * poll:
208c2ecf20Sopenharmony_ci *	NOTE: only one poll value must be given for all cards
218c2ecf20Sopenharmony_ci *	Give the number of samples for each fifo process.
228c2ecf20Sopenharmony_ci *	By default 128 is used. Decrease to reduce delay, increase to
238c2ecf20Sopenharmony_ci *	reduce cpu load. If unsure, don't mess with it!
248c2ecf20Sopenharmony_ci *	A value of 128 will use controller's interrupt. Other values will
258c2ecf20Sopenharmony_ci *	use kernel timer, because the controller will not allow lower values
268c2ecf20Sopenharmony_ci *	than 128.
278c2ecf20Sopenharmony_ci *	Also note that the value depends on the kernel timer frequency.
288c2ecf20Sopenharmony_ci *	If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible.
298c2ecf20Sopenharmony_ci *	If the kernel uses 100 Hz, steps of 80 samples are possible.
308c2ecf20Sopenharmony_ci *	If the kernel uses 300 Hz, steps of about 26 samples are possible.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
348c2ecf20Sopenharmony_ci#include <linux/module.h>
358c2ecf20Sopenharmony_ci#include <linux/pci.h>
368c2ecf20Sopenharmony_ci#include <linux/delay.h>
378c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h>
388c2ecf20Sopenharmony_ci#include <linux/slab.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include "hfc_pci.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const char *hfcpci_revision = "2.0";
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic int HFC_cnt;
458c2ecf20Sopenharmony_cistatic uint debug;
468c2ecf20Sopenharmony_cistatic uint poll, tics;
478c2ecf20Sopenharmony_cistatic struct timer_list hfc_tl;
488c2ecf20Sopenharmony_cistatic unsigned long hfc_jiffies;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil");
518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
528c2ecf20Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR);
538c2ecf20Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cienum {
568c2ecf20Sopenharmony_ci	HFC_CCD_2BD0,
578c2ecf20Sopenharmony_ci	HFC_CCD_B000,
588c2ecf20Sopenharmony_ci	HFC_CCD_B006,
598c2ecf20Sopenharmony_ci	HFC_CCD_B007,
608c2ecf20Sopenharmony_ci	HFC_CCD_B008,
618c2ecf20Sopenharmony_ci	HFC_CCD_B009,
628c2ecf20Sopenharmony_ci	HFC_CCD_B00A,
638c2ecf20Sopenharmony_ci	HFC_CCD_B00B,
648c2ecf20Sopenharmony_ci	HFC_CCD_B00C,
658c2ecf20Sopenharmony_ci	HFC_CCD_B100,
668c2ecf20Sopenharmony_ci	HFC_CCD_B700,
678c2ecf20Sopenharmony_ci	HFC_CCD_B701,
688c2ecf20Sopenharmony_ci	HFC_ASUS_0675,
698c2ecf20Sopenharmony_ci	HFC_BERKOM_A1T,
708c2ecf20Sopenharmony_ci	HFC_BERKOM_TCONCEPT,
718c2ecf20Sopenharmony_ci	HFC_ANIGMA_MC145575,
728c2ecf20Sopenharmony_ci	HFC_ZOLTRIX_2BD0,
738c2ecf20Sopenharmony_ci	HFC_DIGI_DF_M_IOM2_E,
748c2ecf20Sopenharmony_ci	HFC_DIGI_DF_M_E,
758c2ecf20Sopenharmony_ci	HFC_DIGI_DF_M_IOM2_A,
768c2ecf20Sopenharmony_ci	HFC_DIGI_DF_M_A,
778c2ecf20Sopenharmony_ci	HFC_ABOCOM_2BD1,
788c2ecf20Sopenharmony_ci	HFC_SITECOM_DC105V2,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct hfcPCI_hw {
828c2ecf20Sopenharmony_ci	unsigned char		cirm;
838c2ecf20Sopenharmony_ci	unsigned char		ctmt;
848c2ecf20Sopenharmony_ci	unsigned char		clkdel;
858c2ecf20Sopenharmony_ci	unsigned char		states;
868c2ecf20Sopenharmony_ci	unsigned char		conn;
878c2ecf20Sopenharmony_ci	unsigned char		mst_m;
888c2ecf20Sopenharmony_ci	unsigned char		int_m1;
898c2ecf20Sopenharmony_ci	unsigned char		int_m2;
908c2ecf20Sopenharmony_ci	unsigned char		sctrl;
918c2ecf20Sopenharmony_ci	unsigned char		sctrl_r;
928c2ecf20Sopenharmony_ci	unsigned char		sctrl_e;
938c2ecf20Sopenharmony_ci	unsigned char		trm;
948c2ecf20Sopenharmony_ci	unsigned char		fifo_en;
958c2ecf20Sopenharmony_ci	unsigned char		bswapped;
968c2ecf20Sopenharmony_ci	unsigned char		protocol;
978c2ecf20Sopenharmony_ci	int			nt_timer;
988c2ecf20Sopenharmony_ci	unsigned char __iomem	*pci_io; /* start of PCI IO memory */
998c2ecf20Sopenharmony_ci	dma_addr_t		dmahandle;
1008c2ecf20Sopenharmony_ci	void			*fifos; /* FIFO memory */
1018c2ecf20Sopenharmony_ci	int			last_bfifo_cnt[2];
1028c2ecf20Sopenharmony_ci	/* marker saving last b-fifo frame count */
1038c2ecf20Sopenharmony_ci	struct timer_list	timer;
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#define	HFC_CFG_MASTER		1
1078c2ecf20Sopenharmony_ci#define HFC_CFG_SLAVE		2
1088c2ecf20Sopenharmony_ci#define	HFC_CFG_PCM		3
1098c2ecf20Sopenharmony_ci#define HFC_CFG_2HFC		4
1108c2ecf20Sopenharmony_ci#define HFC_CFG_SLAVEHFC	5
1118c2ecf20Sopenharmony_ci#define HFC_CFG_NEG_F0		6
1128c2ecf20Sopenharmony_ci#define HFC_CFG_SW_DD_DU	7
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define FLG_HFC_TIMER_T1	16
1158c2ecf20Sopenharmony_ci#define FLG_HFC_TIMER_T3	17
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define NT_T1_COUNT	1120	/* number of 3.125ms interrupts (3.5s) */
1188c2ecf20Sopenharmony_ci#define NT_T3_COUNT	31	/* number of 3.125ms interrupts (97 ms) */
1198c2ecf20Sopenharmony_ci#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */
1208c2ecf20Sopenharmony_ci#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistruct hfc_pci {
1248c2ecf20Sopenharmony_ci	u_char			subtype;
1258c2ecf20Sopenharmony_ci	u_char			chanlimit;
1268c2ecf20Sopenharmony_ci	u_char			initdone;
1278c2ecf20Sopenharmony_ci	u_long			cfg;
1288c2ecf20Sopenharmony_ci	u_int			irq;
1298c2ecf20Sopenharmony_ci	u_int			irqcnt;
1308c2ecf20Sopenharmony_ci	struct pci_dev		*pdev;
1318c2ecf20Sopenharmony_ci	struct hfcPCI_hw	hw;
1328c2ecf20Sopenharmony_ci	spinlock_t		lock;	/* card lock */
1338c2ecf20Sopenharmony_ci	struct dchannel		dch;
1348c2ecf20Sopenharmony_ci	struct bchannel		bch[2];
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* Interface functions */
1388c2ecf20Sopenharmony_cistatic void
1398c2ecf20Sopenharmony_cienable_hwirq(struct hfc_pci *hc)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE;
1428c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void
1468c2ecf20Sopenharmony_cidisable_hwirq(struct hfc_pci *hc)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE);
1498c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/*
1538c2ecf20Sopenharmony_ci * free hardware resources used by driver
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_cistatic void
1568c2ecf20Sopenharmony_cirelease_io_hfcpci(struct hfc_pci *hc)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	/* disable memory mapped ports + busmaster */
1598c2ecf20Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, 0);
1608c2ecf20Sopenharmony_ci	del_timer(&hc->hw.timer);
1618c2ecf20Sopenharmony_ci	dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
1628c2ecf20Sopenharmony_ci			  hc->hw.dmahandle);
1638c2ecf20Sopenharmony_ci	iounmap(hc->hw.pci_io);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/*
1678c2ecf20Sopenharmony_ci * set mode (NT or TE)
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_cistatic void
1708c2ecf20Sopenharmony_cihfcpci_setmode(struct hfc_pci *hc)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_NT_S0) {
1738c2ecf20Sopenharmony_ci		hc->hw.clkdel = CLKDEL_NT;	/* ST-Bit delay for NT-Mode */
1748c2ecf20Sopenharmony_ci		hc->hw.sctrl |= SCTRL_MODE_NT;	/* NT-MODE */
1758c2ecf20Sopenharmony_ci		hc->hw.states = 1;		/* G1 */
1768c2ecf20Sopenharmony_ci	} else {
1778c2ecf20Sopenharmony_ci		hc->hw.clkdel = CLKDEL_TE;	/* ST-Bit delay for TE-Mode */
1788c2ecf20Sopenharmony_ci		hc->hw.sctrl &= ~SCTRL_MODE_NT;	/* TE-MODE */
1798c2ecf20Sopenharmony_ci		hc->hw.states = 2;		/* F2 */
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel);
1828c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | hc->hw.states);
1838c2ecf20Sopenharmony_ci	udelay(10);
1848c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_STATES, hc->hw.states | 0x40); /* Deactivate */
1858c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/*
1898c2ecf20Sopenharmony_ci * function called to reset the HFC PCI chip. A complete software reset of chip
1908c2ecf20Sopenharmony_ci * and fifos is done.
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_cistatic void
1938c2ecf20Sopenharmony_cireset_hfcpci(struct hfc_pci *hc)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	u_char	val;
1968c2ecf20Sopenharmony_ci	int	cnt = 0;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "reset_hfcpci: entered\n");
1998c2ecf20Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_CHIP_ID);
2008c2ecf20Sopenharmony_ci	printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
2018c2ecf20Sopenharmony_ci	/* enable memory mapped ports, disable busmaster */
2028c2ecf20Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
2038c2ecf20Sopenharmony_ci	disable_hwirq(hc);
2048c2ecf20Sopenharmony_ci	/* enable memory ports + busmaster */
2058c2ecf20Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND,
2068c2ecf20Sopenharmony_ci			      PCI_ENA_MEMIO + PCI_ENA_MASTER);
2078c2ecf20Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_STATUS);
2088c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
2098c2ecf20Sopenharmony_ci	hc->hw.cirm = HFCPCI_RESET;	/* Reset On */
2108c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
2118c2ecf20Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
2128c2ecf20Sopenharmony_ci	mdelay(10);			/* Timeout 10ms */
2138c2ecf20Sopenharmony_ci	hc->hw.cirm = 0;		/* Reset Off */
2148c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
2158c2ecf20Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_STATUS);
2168c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) after reset\n", val);
2178c2ecf20Sopenharmony_ci	while (cnt < 50000) { /* max 50000 us */
2188c2ecf20Sopenharmony_ci		udelay(5);
2198c2ecf20Sopenharmony_ci		cnt += 5;
2208c2ecf20Sopenharmony_ci		val = Read_hfc(hc, HFCPCI_STATUS);
2218c2ecf20Sopenharmony_ci		if (!(val & 2))
2228c2ecf20Sopenharmony_ci			break;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "HFC-PCI status(%x) after %dus\n", val, cnt);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	hc->hw.fifo_en = 0x30;	/* only D fifos enabled */
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	hc->hw.bswapped = 0;	/* no exchange */
2298c2ecf20Sopenharmony_ci	hc->hw.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
2308c2ecf20Sopenharmony_ci	hc->hw.trm = HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
2318c2ecf20Sopenharmony_ci	hc->hw.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */
2328c2ecf20Sopenharmony_ci	hc->hw.sctrl_r = 0;
2338c2ecf20Sopenharmony_ci	hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE;	/* S/T Auto awake */
2348c2ecf20Sopenharmony_ci	hc->hw.mst_m = 0;
2358c2ecf20Sopenharmony_ci	if (test_bit(HFC_CFG_MASTER, &hc->cfg))
2368c2ecf20Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_MASTER;	/* HFC Master Mode */
2378c2ecf20Sopenharmony_ci	if (test_bit(HFC_CFG_NEG_F0, &hc->cfg))
2388c2ecf20Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_F0_NEGATIV;
2398c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
2408c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
2418c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
2428c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	hc->hw.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
2458c2ecf20Sopenharmony_ci		HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
2468c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* Clear already pending ints */
2498c2ecf20Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_INT_S1);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* set NT/TE mode */
2528c2ecf20Sopenharmony_ci	hfcpci_setmode(hc);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
2558c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * Init GCI/IOM2 in master mode
2598c2ecf20Sopenharmony_ci	 * Slots 0 and 1 are set for B-chan 1 and 2
2608c2ecf20Sopenharmony_ci	 * D- and monitor/CI channel are not enabled
2618c2ecf20Sopenharmony_ci	 * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC
2628c2ecf20Sopenharmony_ci	 * STIO2 is used as data input, B1+B2 from IOM->ST
2638c2ecf20Sopenharmony_ci	 * ST B-channel send disabled -> continuous 1s
2648c2ecf20Sopenharmony_ci	 * The IOM slots are always enabled
2658c2ecf20Sopenharmony_ci	 */
2668c2ecf20Sopenharmony_ci	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
2678c2ecf20Sopenharmony_ci		/* set data flow directions: connect B1,B2: HFC to/from PCM */
2688c2ecf20Sopenharmony_ci		hc->hw.conn = 0x09;
2698c2ecf20Sopenharmony_ci	} else {
2708c2ecf20Sopenharmony_ci		hc->hw.conn = 0x36;	/* set data flow directions */
2718c2ecf20Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
2728c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, 0xC0);
2738c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, 0xC1);
2748c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, 0xC0);
2758c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, 0xC1);
2768c2ecf20Sopenharmony_ci		} else {
2778c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, 0x80);
2788c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, 0x81);
2798c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, 0x80);
2808c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, 0x81);
2818c2ecf20Sopenharmony_ci		}
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
2848c2ecf20Sopenharmony_ci	val = Read_hfc(hc, HFCPCI_INT_S2);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/*
2888c2ecf20Sopenharmony_ci * Timer function called when kernel timer expires
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_cistatic void
2918c2ecf20Sopenharmony_cihfcpci_Timer(struct timer_list *t)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct hfc_pci *hc = from_timer(hc, t, hw.timer);
2948c2ecf20Sopenharmony_ci	hc->hw.timer.expires = jiffies + 75;
2958c2ecf20Sopenharmony_ci	/* WD RESET */
2968c2ecf20Sopenharmony_ci/*
2978c2ecf20Sopenharmony_ci *	WriteReg(hc, HFCD_DATA, HFCD_CTMT, hc->hw.ctmt | 0x80);
2988c2ecf20Sopenharmony_ci *	add_timer(&hc->hw.timer);
2998c2ecf20Sopenharmony_ci */
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/*
3048c2ecf20Sopenharmony_ci * select a b-channel entry matching and active
3058c2ecf20Sopenharmony_ci */
3068c2ecf20Sopenharmony_cistatic struct bchannel *
3078c2ecf20Sopenharmony_ciSel_BCS(struct hfc_pci *hc, int channel)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) &&
3108c2ecf20Sopenharmony_ci	    (hc->bch[0].nr & channel))
3118c2ecf20Sopenharmony_ci		return &hc->bch[0];
3128c2ecf20Sopenharmony_ci	else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) &&
3138c2ecf20Sopenharmony_ci		 (hc->bch[1].nr & channel))
3148c2ecf20Sopenharmony_ci		return &hc->bch[1];
3158c2ecf20Sopenharmony_ci	else
3168c2ecf20Sopenharmony_ci		return NULL;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/*
3208c2ecf20Sopenharmony_ci * clear the desired B-channel rx fifo
3218c2ecf20Sopenharmony_ci */
3228c2ecf20Sopenharmony_cistatic void
3238c2ecf20Sopenharmony_cihfcpci_clear_fifo_rx(struct hfc_pci *hc, int fifo)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	u_char		fifo_state;
3268c2ecf20Sopenharmony_ci	struct bzfifo	*bzr;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (fifo) {
3298c2ecf20Sopenharmony_ci		bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
3308c2ecf20Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2RX;
3318c2ecf20Sopenharmony_ci	} else {
3328c2ecf20Sopenharmony_ci		bzr = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
3338c2ecf20Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1RX;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	if (fifo_state)
3368c2ecf20Sopenharmony_ci		hc->hw.fifo_en ^= fifo_state;
3378c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
3388c2ecf20Sopenharmony_ci	hc->hw.last_bfifo_cnt[fifo] = 0;
3398c2ecf20Sopenharmony_ci	bzr->f1 = MAX_B_FRAMES;
3408c2ecf20Sopenharmony_ci	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */
3418c2ecf20Sopenharmony_ci	bzr->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
3428c2ecf20Sopenharmony_ci	bzr->za[MAX_B_FRAMES].z2 = cpu_to_le16(
3438c2ecf20Sopenharmony_ci		le16_to_cpu(bzr->za[MAX_B_FRAMES].z1));
3448c2ecf20Sopenharmony_ci	if (fifo_state)
3458c2ecf20Sopenharmony_ci		hc->hw.fifo_en |= fifo_state;
3468c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/*
3508c2ecf20Sopenharmony_ci * clear the desired B-channel tx fifo
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_cistatic void hfcpci_clear_fifo_tx(struct hfc_pci *hc, int fifo)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	u_char		fifo_state;
3558c2ecf20Sopenharmony_ci	struct bzfifo	*bzt;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (fifo) {
3588c2ecf20Sopenharmony_ci		bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
3598c2ecf20Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B2TX;
3608c2ecf20Sopenharmony_ci	} else {
3618c2ecf20Sopenharmony_ci		bzt = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
3628c2ecf20Sopenharmony_ci		fifo_state = hc->hw.fifo_en & HFCPCI_FIFOEN_B1TX;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci	if (fifo_state)
3658c2ecf20Sopenharmony_ci		hc->hw.fifo_en ^= fifo_state;
3668c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
3678c2ecf20Sopenharmony_ci	if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
3688c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) "
3698c2ecf20Sopenharmony_ci		       "z1(%x) z2(%x) state(%x)\n",
3708c2ecf20Sopenharmony_ci		       fifo, bzt->f1, bzt->f2,
3718c2ecf20Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
3728c2ecf20Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z2),
3738c2ecf20Sopenharmony_ci		       fifo_state);
3748c2ecf20Sopenharmony_ci	bzt->f2 = MAX_B_FRAMES;
3758c2ecf20Sopenharmony_ci	bzt->f1 = bzt->f2;	/* init F pointers to remain constant */
3768c2ecf20Sopenharmony_ci	bzt->za[MAX_B_FRAMES].z1 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 1);
3778c2ecf20Sopenharmony_ci	bzt->za[MAX_B_FRAMES].z2 = cpu_to_le16(B_FIFO_SIZE + B_SUB_VAL - 2);
3788c2ecf20Sopenharmony_ci	if (fifo_state)
3798c2ecf20Sopenharmony_ci		hc->hw.fifo_en |= fifo_state;
3808c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
3818c2ecf20Sopenharmony_ci	if (hc->bch[fifo].debug & DEBUG_HW_BCHANNEL)
3828c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
3838c2ecf20Sopenharmony_ci		       "hfcpci_clear_fifo_tx%d f1(%x) f2(%x) z1(%x) z2(%x)\n",
3848c2ecf20Sopenharmony_ci		       fifo, bzt->f1, bzt->f2,
3858c2ecf20Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z1),
3868c2ecf20Sopenharmony_ci		       le16_to_cpu(bzt->za[MAX_B_FRAMES].z2));
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci/*
3908c2ecf20Sopenharmony_ci * read a complete B-frame out of the buffer
3918c2ecf20Sopenharmony_ci */
3928c2ecf20Sopenharmony_cistatic void
3938c2ecf20Sopenharmony_cihfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
3948c2ecf20Sopenharmony_ci		   u_char *bdata, int count)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	u_char		*ptr, *ptr1, new_f2;
3978c2ecf20Sopenharmony_ci	int		maxlen, new_z2;
3988c2ecf20Sopenharmony_ci	struct zt	*zp;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
4018c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_empty_fifo\n");
4028c2ecf20Sopenharmony_ci	zp = &bz->za[bz->f2];	/* point to Z-Regs */
4038c2ecf20Sopenharmony_ci	new_z2 = le16_to_cpu(zp->z2) + count;	/* new position in fifo */
4048c2ecf20Sopenharmony_ci	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
4058c2ecf20Sopenharmony_ci		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
4068c2ecf20Sopenharmony_ci	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
4078c2ecf20Sopenharmony_ci	if ((count > MAX_DATA_SIZE + 3) || (count < 4) ||
4088c2ecf20Sopenharmony_ci	    (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) {
4098c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW)
4108c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_empty_fifo: incoming packet "
4118c2ecf20Sopenharmony_ci			       "invalid length %d or crc\n", count);
4128c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC
4138c2ecf20Sopenharmony_ci		bch->err_inv++;
4148c2ecf20Sopenharmony_ci#endif
4158c2ecf20Sopenharmony_ci		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
4168c2ecf20Sopenharmony_ci		bz->f2 = new_f2;	/* next buffer */
4178c2ecf20Sopenharmony_ci	} else {
4188c2ecf20Sopenharmony_ci		bch->rx_skb = mI_alloc_skb(count - 3, GFP_ATOMIC);
4198c2ecf20Sopenharmony_ci		if (!bch->rx_skb) {
4208c2ecf20Sopenharmony_ci			printk(KERN_WARNING "HFCPCI: receive out of memory\n");
4218c2ecf20Sopenharmony_ci			return;
4228c2ecf20Sopenharmony_ci		}
4238c2ecf20Sopenharmony_ci		count -= 3;
4248c2ecf20Sopenharmony_ci		ptr = skb_put(bch->rx_skb, count);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL)
4278c2ecf20Sopenharmony_ci			maxlen = count;		/* complete transfer */
4288c2ecf20Sopenharmony_ci		else
4298c2ecf20Sopenharmony_ci			maxlen = B_FIFO_SIZE + B_SUB_VAL -
4308c2ecf20Sopenharmony_ci				le16_to_cpu(zp->z2);	/* maximum */
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL);
4338c2ecf20Sopenharmony_ci		/* start of data */
4348c2ecf20Sopenharmony_ci		memcpy(ptr, ptr1, maxlen);	/* copy data */
4358c2ecf20Sopenharmony_ci		count -= maxlen;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		if (count) {	/* rest remaining */
4388c2ecf20Sopenharmony_ci			ptr += maxlen;
4398c2ecf20Sopenharmony_ci			ptr1 = bdata;	/* start of buffer */
4408c2ecf20Sopenharmony_ci			memcpy(ptr, ptr1, count);	/* rest */
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci		bz->za[new_f2].z2 = cpu_to_le16(new_z2);
4438c2ecf20Sopenharmony_ci		bz->f2 = new_f2;	/* next buffer */
4448c2ecf20Sopenharmony_ci		recv_Bchannel(bch, MISDN_ID_ANY, false);
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/*
4498c2ecf20Sopenharmony_ci * D-channel receive procedure
4508c2ecf20Sopenharmony_ci */
4518c2ecf20Sopenharmony_cistatic int
4528c2ecf20Sopenharmony_cireceive_dmsg(struct hfc_pci *hc)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct dchannel	*dch = &hc->dch;
4558c2ecf20Sopenharmony_ci	int		maxlen;
4568c2ecf20Sopenharmony_ci	int		rcnt, total;
4578c2ecf20Sopenharmony_ci	int		count = 5;
4588c2ecf20Sopenharmony_ci	u_char		*ptr, *ptr1;
4598c2ecf20Sopenharmony_ci	struct dfifo	*df;
4608c2ecf20Sopenharmony_ci	struct zt	*zp;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	df = &((union fifo_area *)(hc->hw.fifos))->d_chan.d_rx;
4638c2ecf20Sopenharmony_ci	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
4648c2ecf20Sopenharmony_ci		zp = &df->za[df->f2 & D_FREG_MASK];
4658c2ecf20Sopenharmony_ci		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
4668c2ecf20Sopenharmony_ci		if (rcnt < 0)
4678c2ecf20Sopenharmony_ci			rcnt += D_FIFO_SIZE;
4688c2ecf20Sopenharmony_ci		rcnt++;
4698c2ecf20Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
4708c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
4718c2ecf20Sopenharmony_ci			       "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)\n",
4728c2ecf20Sopenharmony_ci			       df->f1, df->f2,
4738c2ecf20Sopenharmony_ci			       le16_to_cpu(zp->z1),
4748c2ecf20Sopenharmony_ci			       le16_to_cpu(zp->z2),
4758c2ecf20Sopenharmony_ci			       rcnt);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||
4788c2ecf20Sopenharmony_ci		    (df->data[le16_to_cpu(zp->z1)])) {
4798c2ecf20Sopenharmony_ci			if (dch->debug & DEBUG_HW)
4808c2ecf20Sopenharmony_ci				printk(KERN_DEBUG
4818c2ecf20Sopenharmony_ci				       "empty_fifo hfcpci packet inv. len "
4828c2ecf20Sopenharmony_ci				       "%d or crc %d\n",
4838c2ecf20Sopenharmony_ci				       rcnt,
4848c2ecf20Sopenharmony_ci				       df->data[le16_to_cpu(zp->z1)]);
4858c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC
4868c2ecf20Sopenharmony_ci			cs->err_rx++;
4878c2ecf20Sopenharmony_ci#endif
4888c2ecf20Sopenharmony_ci			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
4898c2ecf20Sopenharmony_ci				(MAX_D_FRAMES + 1);	/* next buffer */
4908c2ecf20Sopenharmony_ci			df->za[df->f2 & D_FREG_MASK].z2 =
4918c2ecf20Sopenharmony_ci				cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) &
4928c2ecf20Sopenharmony_ci					    (D_FIFO_SIZE - 1));
4938c2ecf20Sopenharmony_ci		} else {
4948c2ecf20Sopenharmony_ci			dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
4958c2ecf20Sopenharmony_ci			if (!dch->rx_skb) {
4968c2ecf20Sopenharmony_ci				printk(KERN_WARNING
4978c2ecf20Sopenharmony_ci				       "HFC-PCI: D receive out of memory\n");
4988c2ecf20Sopenharmony_ci				break;
4998c2ecf20Sopenharmony_ci			}
5008c2ecf20Sopenharmony_ci			total = rcnt;
5018c2ecf20Sopenharmony_ci			rcnt -= 3;
5028c2ecf20Sopenharmony_ci			ptr = skb_put(dch->rx_skb, rcnt);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci			if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE)
5058c2ecf20Sopenharmony_ci				maxlen = rcnt;	/* complete transfer */
5068c2ecf20Sopenharmony_ci			else
5078c2ecf20Sopenharmony_ci				maxlen = D_FIFO_SIZE - le16_to_cpu(zp->z2);
5088c2ecf20Sopenharmony_ci			/* maximum */
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci			ptr1 = df->data + le16_to_cpu(zp->z2);
5118c2ecf20Sopenharmony_ci			/* start of data */
5128c2ecf20Sopenharmony_ci			memcpy(ptr, ptr1, maxlen);	/* copy data */
5138c2ecf20Sopenharmony_ci			rcnt -= maxlen;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci			if (rcnt) {	/* rest remaining */
5168c2ecf20Sopenharmony_ci				ptr += maxlen;
5178c2ecf20Sopenharmony_ci				ptr1 = df->data;	/* start of buffer */
5188c2ecf20Sopenharmony_ci				memcpy(ptr, ptr1, rcnt);	/* rest */
5198c2ecf20Sopenharmony_ci			}
5208c2ecf20Sopenharmony_ci			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
5218c2ecf20Sopenharmony_ci				(MAX_D_FRAMES + 1);	/* next buffer */
5228c2ecf20Sopenharmony_ci			df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((
5238c2ecf20Sopenharmony_ci									      le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1));
5248c2ecf20Sopenharmony_ci			recv_Dchannel(dch);
5258c2ecf20Sopenharmony_ci		}
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci	return 1;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci/*
5318c2ecf20Sopenharmony_ci * check for transparent receive data and read max one 'poll' size if avail
5328c2ecf20Sopenharmony_ci */
5338c2ecf20Sopenharmony_cistatic void
5348c2ecf20Sopenharmony_cihfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
5358c2ecf20Sopenharmony_ci			struct bzfifo *txbz, u_char *bdata)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	__le16	*z1r, *z2r, *z1t, *z2t;
5388c2ecf20Sopenharmony_ci	int	new_z2, fcnt_rx, fcnt_tx, maxlen;
5398c2ecf20Sopenharmony_ci	u_char	*ptr, *ptr1;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	z1r = &rxbz->za[MAX_B_FRAMES].z1;	/* pointer to z reg */
5428c2ecf20Sopenharmony_ci	z2r = z1r + 1;
5438c2ecf20Sopenharmony_ci	z1t = &txbz->za[MAX_B_FRAMES].z1;
5448c2ecf20Sopenharmony_ci	z2t = z1t + 1;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
5478c2ecf20Sopenharmony_ci	if (!fcnt_rx)
5488c2ecf20Sopenharmony_ci		return;	/* no data avail */
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (fcnt_rx <= 0)
5518c2ecf20Sopenharmony_ci		fcnt_rx += B_FIFO_SIZE;	/* bytes actually buffered */
5528c2ecf20Sopenharmony_ci	new_z2 = le16_to_cpu(*z2r) + fcnt_rx;	/* new position in fifo */
5538c2ecf20Sopenharmony_ci	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
5548c2ecf20Sopenharmony_ci		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
5578c2ecf20Sopenharmony_ci	if (fcnt_tx <= 0)
5588c2ecf20Sopenharmony_ci		fcnt_tx += B_FIFO_SIZE;
5598c2ecf20Sopenharmony_ci	/* fcnt_tx contains available bytes in tx-fifo */
5608c2ecf20Sopenharmony_ci	fcnt_tx = B_FIFO_SIZE - fcnt_tx;
5618c2ecf20Sopenharmony_ci	/* remaining bytes to send (bytes in tx-fifo) */
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (test_bit(FLG_RX_OFF, &bch->Flags)) {
5648c2ecf20Sopenharmony_ci		bch->dropcnt += fcnt_rx;
5658c2ecf20Sopenharmony_ci		*z2r = cpu_to_le16(new_z2);
5668c2ecf20Sopenharmony_ci		return;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci	maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
5698c2ecf20Sopenharmony_ci	if (maxlen < 0) {
5708c2ecf20Sopenharmony_ci		pr_warn("B%d: No bufferspace for %d bytes\n", bch->nr, fcnt_rx);
5718c2ecf20Sopenharmony_ci	} else {
5728c2ecf20Sopenharmony_ci		ptr = skb_put(bch->rx_skb, fcnt_rx);
5738c2ecf20Sopenharmony_ci		if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
5748c2ecf20Sopenharmony_ci			maxlen = fcnt_rx;	/* complete transfer */
5758c2ecf20Sopenharmony_ci		else
5768c2ecf20Sopenharmony_ci			maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
5778c2ecf20Sopenharmony_ci		/* maximum */
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
5808c2ecf20Sopenharmony_ci		/* start of data */
5818c2ecf20Sopenharmony_ci		memcpy(ptr, ptr1, maxlen);	/* copy data */
5828c2ecf20Sopenharmony_ci		fcnt_rx -= maxlen;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		if (fcnt_rx) {	/* rest remaining */
5858c2ecf20Sopenharmony_ci			ptr += maxlen;
5868c2ecf20Sopenharmony_ci			ptr1 = bdata;	/* start of buffer */
5878c2ecf20Sopenharmony_ci			memcpy(ptr, ptr1, fcnt_rx);	/* rest */
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci		recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	*z2r = cpu_to_le16(new_z2);		/* new position */
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/*
5958c2ecf20Sopenharmony_ci * B-channel main receive routine
5968c2ecf20Sopenharmony_ci */
5978c2ecf20Sopenharmony_cistatic void
5988c2ecf20Sopenharmony_cimain_rec_hfcpci(struct bchannel *bch)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
6018c2ecf20Sopenharmony_ci	int		rcnt, real_fifo;
6028c2ecf20Sopenharmony_ci	int		receive = 0, count = 5;
6038c2ecf20Sopenharmony_ci	struct bzfifo	*txbz, *rxbz;
6048c2ecf20Sopenharmony_ci	u_char		*bdata;
6058c2ecf20Sopenharmony_ci	struct zt	*zp;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
6088c2ecf20Sopenharmony_ci		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
6098c2ecf20Sopenharmony_ci		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
6108c2ecf20Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
6118c2ecf20Sopenharmony_ci		real_fifo = 1;
6128c2ecf20Sopenharmony_ci	} else {
6138c2ecf20Sopenharmony_ci		rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
6148c2ecf20Sopenharmony_ci		txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
6158c2ecf20Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
6168c2ecf20Sopenharmony_ci		real_fifo = 0;
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ciBegin:
6198c2ecf20Sopenharmony_ci	count--;
6208c2ecf20Sopenharmony_ci	if (rxbz->f1 != rxbz->f2) {
6218c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
6228c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
6238c2ecf20Sopenharmony_ci			       bch->nr, rxbz->f1, rxbz->f2);
6248c2ecf20Sopenharmony_ci		zp = &rxbz->za[rxbz->f2];
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
6278c2ecf20Sopenharmony_ci		if (rcnt < 0)
6288c2ecf20Sopenharmony_ci			rcnt += B_FIFO_SIZE;
6298c2ecf20Sopenharmony_ci		rcnt++;
6308c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
6318c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
6328c2ecf20Sopenharmony_ci			       "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
6338c2ecf20Sopenharmony_ci			       bch->nr, le16_to_cpu(zp->z1),
6348c2ecf20Sopenharmony_ci			       le16_to_cpu(zp->z2), rcnt);
6358c2ecf20Sopenharmony_ci		hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
6368c2ecf20Sopenharmony_ci		rcnt = rxbz->f1 - rxbz->f2;
6378c2ecf20Sopenharmony_ci		if (rcnt < 0)
6388c2ecf20Sopenharmony_ci			rcnt += MAX_B_FRAMES + 1;
6398c2ecf20Sopenharmony_ci		if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
6408c2ecf20Sopenharmony_ci			rcnt = 0;
6418c2ecf20Sopenharmony_ci			hfcpci_clear_fifo_rx(hc, real_fifo);
6428c2ecf20Sopenharmony_ci		}
6438c2ecf20Sopenharmony_ci		hc->hw.last_bfifo_cnt[real_fifo] = rcnt;
6448c2ecf20Sopenharmony_ci		if (rcnt > 1)
6458c2ecf20Sopenharmony_ci			receive = 1;
6468c2ecf20Sopenharmony_ci		else
6478c2ecf20Sopenharmony_ci			receive = 0;
6488c2ecf20Sopenharmony_ci	} else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
6498c2ecf20Sopenharmony_ci		hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
6508c2ecf20Sopenharmony_ci		return;
6518c2ecf20Sopenharmony_ci	} else
6528c2ecf20Sopenharmony_ci		receive = 0;
6538c2ecf20Sopenharmony_ci	if (count && receive)
6548c2ecf20Sopenharmony_ci		goto Begin;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci/*
6598c2ecf20Sopenharmony_ci * D-channel send routine
6608c2ecf20Sopenharmony_ci */
6618c2ecf20Sopenharmony_cistatic void
6628c2ecf20Sopenharmony_cihfcpci_fill_dfifo(struct hfc_pci *hc)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	struct dchannel	*dch = &hc->dch;
6658c2ecf20Sopenharmony_ci	int		fcnt;
6668c2ecf20Sopenharmony_ci	int		count, new_z1, maxlen;
6678c2ecf20Sopenharmony_ci	struct dfifo	*df;
6688c2ecf20Sopenharmony_ci	u_char		*src, *dst, new_f1;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if ((dch->debug & DEBUG_HW_DCHANNEL) && !(dch->debug & DEBUG_HW_DFIFO))
6718c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s\n", __func__);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (!dch->tx_skb)
6748c2ecf20Sopenharmony_ci		return;
6758c2ecf20Sopenharmony_ci	count = dch->tx_skb->len - dch->tx_idx;
6768c2ecf20Sopenharmony_ci	if (count <= 0)
6778c2ecf20Sopenharmony_ci		return;
6788c2ecf20Sopenharmony_ci	df = &((union fifo_area *) (hc->hw.fifos))->d_chan.d_tx;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	if (dch->debug & DEBUG_HW_DFIFO)
6818c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s:f1(%d) f2(%d) z1(f1)(%x)\n", __func__,
6828c2ecf20Sopenharmony_ci		       df->f1, df->f2,
6838c2ecf20Sopenharmony_ci		       le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1));
6848c2ecf20Sopenharmony_ci	fcnt = df->f1 - df->f2;	/* frame count actually buffered */
6858c2ecf20Sopenharmony_ci	if (fcnt < 0)
6868c2ecf20Sopenharmony_ci		fcnt += (MAX_D_FRAMES + 1);	/* if wrap around */
6878c2ecf20Sopenharmony_ci	if (fcnt > (MAX_D_FRAMES - 1)) {
6888c2ecf20Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
6898c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
6908c2ecf20Sopenharmony_ci			       "hfcpci_fill_Dfifo more as 14 frames\n");
6918c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC
6928c2ecf20Sopenharmony_ci		cs->err_tx++;
6938c2ecf20Sopenharmony_ci#endif
6948c2ecf20Sopenharmony_ci		return;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci	/* now determine free bytes in FIFO buffer */
6978c2ecf20Sopenharmony_ci	maxlen = le16_to_cpu(df->za[df->f2 & D_FREG_MASK].z2) -
6988c2ecf20Sopenharmony_ci		le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) - 1;
6998c2ecf20Sopenharmony_ci	if (maxlen <= 0)
7008c2ecf20Sopenharmony_ci		maxlen += D_FIFO_SIZE;	/* count now contains available bytes */
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (dch->debug & DEBUG_HW_DCHANNEL)
7038c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_fill_Dfifo count(%d/%d)\n",
7048c2ecf20Sopenharmony_ci		       count, maxlen);
7058c2ecf20Sopenharmony_ci	if (count > maxlen) {
7068c2ecf20Sopenharmony_ci		if (dch->debug & DEBUG_HW_DCHANNEL)
7078c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_Dfifo no fifo mem\n");
7088c2ecf20Sopenharmony_ci		return;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci	new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) &
7118c2ecf20Sopenharmony_ci		(D_FIFO_SIZE - 1);
7128c2ecf20Sopenharmony_ci	new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1);
7138c2ecf20Sopenharmony_ci	src = dch->tx_skb->data + dch->tx_idx;	/* source pointer */
7148c2ecf20Sopenharmony_ci	dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
7158c2ecf20Sopenharmony_ci	maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1);
7168c2ecf20Sopenharmony_ci	/* end fifo */
7178c2ecf20Sopenharmony_ci	if (maxlen > count)
7188c2ecf20Sopenharmony_ci		maxlen = count;	/* limit size */
7198c2ecf20Sopenharmony_ci	memcpy(dst, src, maxlen);	/* first copy */
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	count -= maxlen;	/* remaining bytes */
7228c2ecf20Sopenharmony_ci	if (count) {
7238c2ecf20Sopenharmony_ci		dst = df->data;	/* start of buffer */
7248c2ecf20Sopenharmony_ci		src += maxlen;	/* new position */
7258c2ecf20Sopenharmony_ci		memcpy(dst, src, count);
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci	df->za[new_f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
7288c2ecf20Sopenharmony_ci	/* for next buffer */
7298c2ecf20Sopenharmony_ci	df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1);
7308c2ecf20Sopenharmony_ci	/* new pos actual buffer */
7318c2ecf20Sopenharmony_ci	df->f1 = new_f1;	/* next frame */
7328c2ecf20Sopenharmony_ci	dch->tx_idx = dch->tx_skb->len;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci/*
7368c2ecf20Sopenharmony_ci * B-channel send routine
7378c2ecf20Sopenharmony_ci */
7388c2ecf20Sopenharmony_cistatic void
7398c2ecf20Sopenharmony_cihfcpci_fill_fifo(struct bchannel *bch)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
7428c2ecf20Sopenharmony_ci	int		maxlen, fcnt;
7438c2ecf20Sopenharmony_ci	int		count, new_z1;
7448c2ecf20Sopenharmony_ci	struct bzfifo	*bz;
7458c2ecf20Sopenharmony_ci	u_char		*bdata;
7468c2ecf20Sopenharmony_ci	u_char		new_f1, *src, *dst;
7478c2ecf20Sopenharmony_ci	__le16 *z1t, *z2t;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
7508c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s\n", __func__);
7518c2ecf20Sopenharmony_ci	if ((!bch->tx_skb) || bch->tx_skb->len == 0) {
7528c2ecf20Sopenharmony_ci		if (!test_bit(FLG_FILLEMPTY, &bch->Flags) &&
7538c2ecf20Sopenharmony_ci		    !test_bit(FLG_TRANSPARENT, &bch->Flags))
7548c2ecf20Sopenharmony_ci			return;
7558c2ecf20Sopenharmony_ci		count = HFCPCI_FILLEMPTY;
7568c2ecf20Sopenharmony_ci	} else {
7578c2ecf20Sopenharmony_ci		count = bch->tx_skb->len - bch->tx_idx;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
7608c2ecf20Sopenharmony_ci		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
7618c2ecf20Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2;
7628c2ecf20Sopenharmony_ci	} else {
7638c2ecf20Sopenharmony_ci		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
7648c2ecf20Sopenharmony_ci		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b1;
7658c2ecf20Sopenharmony_ci	}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
7688c2ecf20Sopenharmony_ci		z1t = &bz->za[MAX_B_FRAMES].z1;
7698c2ecf20Sopenharmony_ci		z2t = z1t + 1;
7708c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
7718c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_fifo_trans ch(%x) "
7728c2ecf20Sopenharmony_ci			       "cnt(%d) z1(%x) z2(%x)\n", bch->nr, count,
7738c2ecf20Sopenharmony_ci			       le16_to_cpu(*z1t), le16_to_cpu(*z2t));
7748c2ecf20Sopenharmony_ci		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
7758c2ecf20Sopenharmony_ci		if (fcnt <= 0)
7768c2ecf20Sopenharmony_ci			fcnt += B_FIFO_SIZE;
7778c2ecf20Sopenharmony_ci		if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
7788c2ecf20Sopenharmony_ci			/* fcnt contains available bytes in fifo */
7798c2ecf20Sopenharmony_ci			if (count > fcnt)
7808c2ecf20Sopenharmony_ci				count = fcnt;
7818c2ecf20Sopenharmony_ci			new_z1 = le16_to_cpu(*z1t) + count;
7828c2ecf20Sopenharmony_ci			/* new buffer Position */
7838c2ecf20Sopenharmony_ci			if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
7848c2ecf20Sopenharmony_ci				new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
7858c2ecf20Sopenharmony_ci			dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
7868c2ecf20Sopenharmony_ci			maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
7878c2ecf20Sopenharmony_ci			/* end of fifo */
7888c2ecf20Sopenharmony_ci			if (bch->debug & DEBUG_HW_BFIFO)
7898c2ecf20Sopenharmony_ci				printk(KERN_DEBUG "hfcpci_FFt fillempty "
7908c2ecf20Sopenharmony_ci				       "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n",
7918c2ecf20Sopenharmony_ci				       fcnt, maxlen, new_z1, dst);
7928c2ecf20Sopenharmony_ci			if (maxlen > count)
7938c2ecf20Sopenharmony_ci				maxlen = count;		/* limit size */
7948c2ecf20Sopenharmony_ci			memset(dst, bch->fill[0], maxlen); /* first copy */
7958c2ecf20Sopenharmony_ci			count -= maxlen;		/* remaining bytes */
7968c2ecf20Sopenharmony_ci			if (count) {
7978c2ecf20Sopenharmony_ci				dst = bdata;		/* start of buffer */
7988c2ecf20Sopenharmony_ci				memset(dst, bch->fill[0], count);
7998c2ecf20Sopenharmony_ci			}
8008c2ecf20Sopenharmony_ci			*z1t = cpu_to_le16(new_z1);	/* now send data */
8018c2ecf20Sopenharmony_ci			return;
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci		/* fcnt contains available bytes in fifo */
8048c2ecf20Sopenharmony_ci		fcnt = B_FIFO_SIZE - fcnt;
8058c2ecf20Sopenharmony_ci		/* remaining bytes to send (bytes in fifo) */
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	next_t_frame:
8088c2ecf20Sopenharmony_ci		count = bch->tx_skb->len - bch->tx_idx;
8098c2ecf20Sopenharmony_ci		/* maximum fill shall be poll*2 */
8108c2ecf20Sopenharmony_ci		if (count > (poll << 1) - fcnt)
8118c2ecf20Sopenharmony_ci			count = (poll << 1) - fcnt;
8128c2ecf20Sopenharmony_ci		if (count <= 0)
8138c2ecf20Sopenharmony_ci			return;
8148c2ecf20Sopenharmony_ci		/* data is suitable for fifo */
8158c2ecf20Sopenharmony_ci		new_z1 = le16_to_cpu(*z1t) + count;
8168c2ecf20Sopenharmony_ci		/* new buffer Position */
8178c2ecf20Sopenharmony_ci		if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
8188c2ecf20Sopenharmony_ci			new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
8198c2ecf20Sopenharmony_ci		src = bch->tx_skb->data + bch->tx_idx;
8208c2ecf20Sopenharmony_ci		/* source pointer */
8218c2ecf20Sopenharmony_ci		dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
8228c2ecf20Sopenharmony_ci		maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
8238c2ecf20Sopenharmony_ci		/* end of fifo */
8248c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BFIFO)
8258c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_FFt fcnt(%d) "
8268c2ecf20Sopenharmony_ci			       "maxl(%d) nz1(%x) dst(%p)\n",
8278c2ecf20Sopenharmony_ci			       fcnt, maxlen, new_z1, dst);
8288c2ecf20Sopenharmony_ci		fcnt += count;
8298c2ecf20Sopenharmony_ci		bch->tx_idx += count;
8308c2ecf20Sopenharmony_ci		if (maxlen > count)
8318c2ecf20Sopenharmony_ci			maxlen = count;		/* limit size */
8328c2ecf20Sopenharmony_ci		memcpy(dst, src, maxlen);	/* first copy */
8338c2ecf20Sopenharmony_ci		count -= maxlen;	/* remaining bytes */
8348c2ecf20Sopenharmony_ci		if (count) {
8358c2ecf20Sopenharmony_ci			dst = bdata;	/* start of buffer */
8368c2ecf20Sopenharmony_ci			src += maxlen;	/* new position */
8378c2ecf20Sopenharmony_ci			memcpy(dst, src, count);
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci		*z1t = cpu_to_le16(new_z1);	/* now send data */
8408c2ecf20Sopenharmony_ci		if (bch->tx_idx < bch->tx_skb->len)
8418c2ecf20Sopenharmony_ci			return;
8428c2ecf20Sopenharmony_ci		dev_kfree_skb_any(bch->tx_skb);
8438c2ecf20Sopenharmony_ci		if (get_next_bframe(bch))
8448c2ecf20Sopenharmony_ci			goto next_t_frame;
8458c2ecf20Sopenharmony_ci		return;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
8488c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
8498c2ecf20Sopenharmony_ci		       "%s: ch(%x) f1(%d) f2(%d) z1(f1)(%x)\n",
8508c2ecf20Sopenharmony_ci		       __func__, bch->nr, bz->f1, bz->f2,
8518c2ecf20Sopenharmony_ci		       bz->za[bz->f1].z1);
8528c2ecf20Sopenharmony_ci	fcnt = bz->f1 - bz->f2;	/* frame count actually buffered */
8538c2ecf20Sopenharmony_ci	if (fcnt < 0)
8548c2ecf20Sopenharmony_ci		fcnt += (MAX_B_FRAMES + 1);	/* if wrap around */
8558c2ecf20Sopenharmony_ci	if (fcnt > (MAX_B_FRAMES - 1)) {
8568c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
8578c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
8588c2ecf20Sopenharmony_ci			       "hfcpci_fill_Bfifo more as 14 frames\n");
8598c2ecf20Sopenharmony_ci		return;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci	/* now determine free bytes in FIFO buffer */
8628c2ecf20Sopenharmony_ci	maxlen = le16_to_cpu(bz->za[bz->f2].z2) -
8638c2ecf20Sopenharmony_ci		le16_to_cpu(bz->za[bz->f1].z1) - 1;
8648c2ecf20Sopenharmony_ci	if (maxlen <= 0)
8658c2ecf20Sopenharmony_ci		maxlen += B_FIFO_SIZE;	/* count now contains available bytes */
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
8688c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "hfcpci_fill_fifo ch(%x) count(%d/%d)\n",
8698c2ecf20Sopenharmony_ci		       bch->nr, count, maxlen);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (maxlen < count) {
8728c2ecf20Sopenharmony_ci		if (bch->debug & DEBUG_HW_BCHANNEL)
8738c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci_fill_fifo no fifo mem\n");
8748c2ecf20Sopenharmony_ci		return;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci	new_z1 = le16_to_cpu(bz->za[bz->f1].z1) + count;
8778c2ecf20Sopenharmony_ci	/* new buffer Position */
8788c2ecf20Sopenharmony_ci	if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
8798c2ecf20Sopenharmony_ci		new_z1 -= B_FIFO_SIZE;	/* buffer wrap */
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES);
8828c2ecf20Sopenharmony_ci	src = bch->tx_skb->data + bch->tx_idx;	/* source pointer */
8838c2ecf20Sopenharmony_ci	dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL);
8848c2ecf20Sopenharmony_ci	maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1);
8858c2ecf20Sopenharmony_ci	/* end fifo */
8868c2ecf20Sopenharmony_ci	if (maxlen > count)
8878c2ecf20Sopenharmony_ci		maxlen = count;	/* limit size */
8888c2ecf20Sopenharmony_ci	memcpy(dst, src, maxlen);	/* first copy */
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	count -= maxlen;	/* remaining bytes */
8918c2ecf20Sopenharmony_ci	if (count) {
8928c2ecf20Sopenharmony_ci		dst = bdata;	/* start of buffer */
8938c2ecf20Sopenharmony_ci		src += maxlen;	/* new position */
8948c2ecf20Sopenharmony_ci		memcpy(dst, src, count);
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci	bz->za[new_f1].z1 = cpu_to_le16(new_z1);	/* for next buffer */
8978c2ecf20Sopenharmony_ci	bz->f1 = new_f1;	/* next frame */
8988c2ecf20Sopenharmony_ci	dev_kfree_skb_any(bch->tx_skb);
8998c2ecf20Sopenharmony_ci	get_next_bframe(bch);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci/*
9058c2ecf20Sopenharmony_ci * handle L1 state changes TE
9068c2ecf20Sopenharmony_ci */
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic void
9098c2ecf20Sopenharmony_ciph_state_te(struct dchannel *dch)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	if (dch->debug)
9128c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: TE newstate %x\n",
9138c2ecf20Sopenharmony_ci		       __func__, dch->state);
9148c2ecf20Sopenharmony_ci	switch (dch->state) {
9158c2ecf20Sopenharmony_ci	case 0:
9168c2ecf20Sopenharmony_ci		l1_event(dch->l1, HW_RESET_IND);
9178c2ecf20Sopenharmony_ci		break;
9188c2ecf20Sopenharmony_ci	case 3:
9198c2ecf20Sopenharmony_ci		l1_event(dch->l1, HW_DEACT_IND);
9208c2ecf20Sopenharmony_ci		break;
9218c2ecf20Sopenharmony_ci	case 5:
9228c2ecf20Sopenharmony_ci	case 8:
9238c2ecf20Sopenharmony_ci		l1_event(dch->l1, ANYSIGNAL);
9248c2ecf20Sopenharmony_ci		break;
9258c2ecf20Sopenharmony_ci	case 6:
9268c2ecf20Sopenharmony_ci		l1_event(dch->l1, INFO2);
9278c2ecf20Sopenharmony_ci		break;
9288c2ecf20Sopenharmony_ci	case 7:
9298c2ecf20Sopenharmony_ci		l1_event(dch->l1, INFO4_P8);
9308c2ecf20Sopenharmony_ci		break;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci/*
9358c2ecf20Sopenharmony_ci * handle L1 state changes NT
9368c2ecf20Sopenharmony_ci */
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic void
9398c2ecf20Sopenharmony_cihandle_nt_timer3(struct dchannel *dch) {
9408c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
9438c2ecf20Sopenharmony_ci	hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
9448c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
9458c2ecf20Sopenharmony_ci	hc->hw.nt_timer = 0;
9468c2ecf20Sopenharmony_ci	test_and_set_bit(FLG_ACTIVE, &dch->Flags);
9478c2ecf20Sopenharmony_ci	if (test_bit(HFC_CFG_MASTER, &hc->cfg))
9488c2ecf20Sopenharmony_ci		hc->hw.mst_m |= HFCPCI_MASTER;
9498c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
9508c2ecf20Sopenharmony_ci	_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
9518c2ecf20Sopenharmony_ci		    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic void
9558c2ecf20Sopenharmony_ciph_state_nt(struct dchannel *dch)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (dch->debug)
9608c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: NT newstate %x\n",
9618c2ecf20Sopenharmony_ci		       __func__, dch->state);
9628c2ecf20Sopenharmony_ci	switch (dch->state) {
9638c2ecf20Sopenharmony_ci	case 2:
9648c2ecf20Sopenharmony_ci		if (hc->hw.nt_timer < 0) {
9658c2ecf20Sopenharmony_ci			hc->hw.nt_timer = 0;
9668c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
9678c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
9688c2ecf20Sopenharmony_ci			hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
9698c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
9708c2ecf20Sopenharmony_ci			/* Clear already pending ints */
9718c2ecf20Sopenharmony_ci			(void) Read_hfc(hc, HFCPCI_INT_S1);
9728c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
9738c2ecf20Sopenharmony_ci			udelay(10);
9748c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 4);
9758c2ecf20Sopenharmony_ci			dch->state = 4;
9768c2ecf20Sopenharmony_ci		} else if (hc->hw.nt_timer == 0) {
9778c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
9788c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
9798c2ecf20Sopenharmony_ci			hc->hw.nt_timer = NT_T1_COUNT;
9808c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
9818c2ecf20Sopenharmony_ci			hc->hw.ctmt |= HFCPCI_TIM3_125;
9828c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
9838c2ecf20Sopenharmony_ci				  HFCPCI_CLTIMER);
9848c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
9858c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_HFC_TIMER_T1, &dch->Flags);
9868c2ecf20Sopenharmony_ci			/* allow G2 -> G3 transition */
9878c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
9888c2ecf20Sopenharmony_ci		} else {
9898c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);
9908c2ecf20Sopenharmony_ci		}
9918c2ecf20Sopenharmony_ci		break;
9928c2ecf20Sopenharmony_ci	case 1:
9938c2ecf20Sopenharmony_ci		hc->hw.nt_timer = 0;
9948c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
9958c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
9968c2ecf20Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
9978c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
9988c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
9998c2ecf20Sopenharmony_ci		hc->hw.mst_m &= ~HFCPCI_MASTER;
10008c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
10018c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
10028c2ecf20Sopenharmony_ci		_queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
10038c2ecf20Sopenharmony_ci			    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
10048c2ecf20Sopenharmony_ci		break;
10058c2ecf20Sopenharmony_ci	case 4:
10068c2ecf20Sopenharmony_ci		hc->hw.nt_timer = 0;
10078c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T3, &dch->Flags);
10088c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
10098c2ecf20Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
10108c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
10118c2ecf20Sopenharmony_ci		break;
10128c2ecf20Sopenharmony_ci	case 3:
10138c2ecf20Sopenharmony_ci		if (!test_and_set_bit(FLG_HFC_TIMER_T3, &dch->Flags)) {
10148c2ecf20Sopenharmony_ci			if (!test_and_clear_bit(FLG_L2_ACTIVATED,
10158c2ecf20Sopenharmony_ci						&dch->Flags)) {
10168c2ecf20Sopenharmony_ci				handle_nt_timer3(dch);
10178c2ecf20Sopenharmony_ci				break;
10188c2ecf20Sopenharmony_ci			}
10198c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_HFC_TIMER_T1, &dch->Flags);
10208c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_TIMER;
10218c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
10228c2ecf20Sopenharmony_ci			hc->hw.nt_timer = NT_T3_COUNT;
10238c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER;
10248c2ecf20Sopenharmony_ci			hc->hw.ctmt |= HFCPCI_TIM3_125;
10258c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt |
10268c2ecf20Sopenharmony_ci				  HFCPCI_CLTIMER);
10278c2ecf20Sopenharmony_ci		}
10288c2ecf20Sopenharmony_ci		break;
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_cistatic void
10338c2ecf20Sopenharmony_ciph_state(struct dchannel *dch)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = dch->hw;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_NT_S0) {
10388c2ecf20Sopenharmony_ci		if (test_bit(FLG_HFC_TIMER_T3, &dch->Flags) &&
10398c2ecf20Sopenharmony_ci		    hc->hw.nt_timer < 0)
10408c2ecf20Sopenharmony_ci			handle_nt_timer3(dch);
10418c2ecf20Sopenharmony_ci		else
10428c2ecf20Sopenharmony_ci			ph_state_nt(dch);
10438c2ecf20Sopenharmony_ci	} else
10448c2ecf20Sopenharmony_ci		ph_state_te(dch);
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci/*
10488c2ecf20Sopenharmony_ci * Layer 1 callback function
10498c2ecf20Sopenharmony_ci */
10508c2ecf20Sopenharmony_cistatic int
10518c2ecf20Sopenharmony_cihfc_l1callback(struct dchannel *dch, u_int cmd)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	switch (cmd) {
10568c2ecf20Sopenharmony_ci	case INFO3_P8:
10578c2ecf20Sopenharmony_ci	case INFO3_P10:
10588c2ecf20Sopenharmony_ci		if (test_bit(HFC_CFG_MASTER, &hc->cfg))
10598c2ecf20Sopenharmony_ci			hc->hw.mst_m |= HFCPCI_MASTER;
10608c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
10618c2ecf20Sopenharmony_ci		break;
10628c2ecf20Sopenharmony_ci	case HW_RESET_REQ:
10638c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3);
10648c2ecf20Sopenharmony_ci		/* HFC ST 3 */
10658c2ecf20Sopenharmony_ci		udelay(6);
10668c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, 3);	/* HFC ST 2 */
10678c2ecf20Sopenharmony_ci		if (test_bit(HFC_CFG_MASTER, &hc->cfg))
10688c2ecf20Sopenharmony_ci			hc->hw.mst_m |= HFCPCI_MASTER;
10698c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
10708c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
10718c2ecf20Sopenharmony_ci			  HFCPCI_DO_ACTION);
10728c2ecf20Sopenharmony_ci		l1_event(dch->l1, HW_POWERUP_IND);
10738c2ecf20Sopenharmony_ci		break;
10748c2ecf20Sopenharmony_ci	case HW_DEACT_REQ:
10758c2ecf20Sopenharmony_ci		hc->hw.mst_m &= ~HFCPCI_MASTER;
10768c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
10778c2ecf20Sopenharmony_ci		skb_queue_purge(&dch->squeue);
10788c2ecf20Sopenharmony_ci		if (dch->tx_skb) {
10798c2ecf20Sopenharmony_ci			dev_kfree_skb(dch->tx_skb);
10808c2ecf20Sopenharmony_ci			dch->tx_skb = NULL;
10818c2ecf20Sopenharmony_ci		}
10828c2ecf20Sopenharmony_ci		dch->tx_idx = 0;
10838c2ecf20Sopenharmony_ci		if (dch->rx_skb) {
10848c2ecf20Sopenharmony_ci			dev_kfree_skb(dch->rx_skb);
10858c2ecf20Sopenharmony_ci			dch->rx_skb = NULL;
10868c2ecf20Sopenharmony_ci		}
10878c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
10888c2ecf20Sopenharmony_ci		if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
10898c2ecf20Sopenharmony_ci			del_timer(&dch->timer);
10908c2ecf20Sopenharmony_ci		break;
10918c2ecf20Sopenharmony_ci	case HW_POWERUP_REQ:
10928c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION);
10938c2ecf20Sopenharmony_ci		break;
10948c2ecf20Sopenharmony_ci	case PH_ACTIVATE_IND:
10958c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_ACTIVE, &dch->Flags);
10968c2ecf20Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
10978c2ecf20Sopenharmony_ci			    GFP_ATOMIC);
10988c2ecf20Sopenharmony_ci		break;
10998c2ecf20Sopenharmony_ci	case PH_DEACTIVATE_IND:
11008c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
11018c2ecf20Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
11028c2ecf20Sopenharmony_ci			    GFP_ATOMIC);
11038c2ecf20Sopenharmony_ci		break;
11048c2ecf20Sopenharmony_ci	default:
11058c2ecf20Sopenharmony_ci		if (dch->debug & DEBUG_HW)
11068c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
11078c2ecf20Sopenharmony_ci			       __func__, cmd);
11088c2ecf20Sopenharmony_ci		return -1;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci/*
11148c2ecf20Sopenharmony_ci * Interrupt handler
11158c2ecf20Sopenharmony_ci */
11168c2ecf20Sopenharmony_cistatic inline void
11178c2ecf20Sopenharmony_citx_birq(struct bchannel *bch)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
11208c2ecf20Sopenharmony_ci		hfcpci_fill_fifo(bch);
11218c2ecf20Sopenharmony_ci	else {
11228c2ecf20Sopenharmony_ci		dev_kfree_skb_any(bch->tx_skb);
11238c2ecf20Sopenharmony_ci		if (get_next_bframe(bch))
11248c2ecf20Sopenharmony_ci			hfcpci_fill_fifo(bch);
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic inline void
11298c2ecf20Sopenharmony_citx_dirq(struct dchannel *dch)
11308c2ecf20Sopenharmony_ci{
11318c2ecf20Sopenharmony_ci	if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len)
11328c2ecf20Sopenharmony_ci		hfcpci_fill_dfifo(dch->hw);
11338c2ecf20Sopenharmony_ci	else {
11348c2ecf20Sopenharmony_ci		dev_kfree_skb(dch->tx_skb);
11358c2ecf20Sopenharmony_ci		if (get_next_dframe(dch))
11368c2ecf20Sopenharmony_ci			hfcpci_fill_dfifo(dch->hw);
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_cistatic irqreturn_t
11418c2ecf20Sopenharmony_cihfcpci_int(int intno, void *dev_id)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = dev_id;
11448c2ecf20Sopenharmony_ci	u_char		exval;
11458c2ecf20Sopenharmony_ci	struct bchannel	*bch;
11468c2ecf20Sopenharmony_ci	u_char		val, stat;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	spin_lock(&hc->lock);
11498c2ecf20Sopenharmony_ci	if (!(hc->hw.int_m2 & 0x08)) {
11508c2ecf20Sopenharmony_ci		spin_unlock(&hc->lock);
11518c2ecf20Sopenharmony_ci		return IRQ_NONE; /* not initialised */
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci	stat = Read_hfc(hc, HFCPCI_STATUS);
11548c2ecf20Sopenharmony_ci	if (HFCPCI_ANYINT & stat) {
11558c2ecf20Sopenharmony_ci		val = Read_hfc(hc, HFCPCI_INT_S1);
11568c2ecf20Sopenharmony_ci		if (hc->dch.debug & DEBUG_HW_DCHANNEL)
11578c2ecf20Sopenharmony_ci			printk(KERN_DEBUG
11588c2ecf20Sopenharmony_ci			       "HFC-PCI: stat(%02x) s1(%02x)\n", stat, val);
11598c2ecf20Sopenharmony_ci	} else {
11608c2ecf20Sopenharmony_ci		/* shared */
11618c2ecf20Sopenharmony_ci		spin_unlock(&hc->lock);
11628c2ecf20Sopenharmony_ci		return IRQ_NONE;
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci	hc->irqcnt++;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (hc->dch.debug & DEBUG_HW_DCHANNEL)
11678c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "HFC-PCI irq %x\n", val);
11688c2ecf20Sopenharmony_ci	val &= hc->hw.int_m1;
11698c2ecf20Sopenharmony_ci	if (val & 0x40) {	/* state machine irq */
11708c2ecf20Sopenharmony_ci		exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
11718c2ecf20Sopenharmony_ci		if (hc->dch.debug & DEBUG_HW_DCHANNEL)
11728c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "ph_state chg %d->%d\n",
11738c2ecf20Sopenharmony_ci			       hc->dch.state, exval);
11748c2ecf20Sopenharmony_ci		hc->dch.state = exval;
11758c2ecf20Sopenharmony_ci		schedule_event(&hc->dch, FLG_PHCHANGE);
11768c2ecf20Sopenharmony_ci		val &= ~0x40;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci	if (val & 0x80) {	/* timer irq */
11798c2ecf20Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
11808c2ecf20Sopenharmony_ci			if ((--hc->hw.nt_timer) < 0)
11818c2ecf20Sopenharmony_ci				schedule_event(&hc->dch, FLG_PHCHANGE);
11828c2ecf20Sopenharmony_ci		}
11838c2ecf20Sopenharmony_ci		val &= ~0x80;
11848c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci	if (val & 0x08) {	/* B1 rx */
11878c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
11888c2ecf20Sopenharmony_ci		if (bch)
11898c2ecf20Sopenharmony_ci			main_rec_hfcpci(bch);
11908c2ecf20Sopenharmony_ci		else if (hc->dch.debug)
11918c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n");
11928c2ecf20Sopenharmony_ci	}
11938c2ecf20Sopenharmony_ci	if (val & 0x10) {	/* B2 rx */
11948c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, 2);
11958c2ecf20Sopenharmony_ci		if (bch)
11968c2ecf20Sopenharmony_ci			main_rec_hfcpci(bch);
11978c2ecf20Sopenharmony_ci		else if (hc->dch.debug)
11988c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n");
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci	if (val & 0x01) {	/* B1 tx */
12018c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
12028c2ecf20Sopenharmony_ci		if (bch)
12038c2ecf20Sopenharmony_ci			tx_birq(bch);
12048c2ecf20Sopenharmony_ci		else if (hc->dch.debug)
12058c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n");
12068c2ecf20Sopenharmony_ci	}
12078c2ecf20Sopenharmony_ci	if (val & 0x02) {	/* B2 tx */
12088c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, 2);
12098c2ecf20Sopenharmony_ci		if (bch)
12108c2ecf20Sopenharmony_ci			tx_birq(bch);
12118c2ecf20Sopenharmony_ci		else if (hc->dch.debug)
12128c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n");
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci	if (val & 0x20)		/* D rx */
12158c2ecf20Sopenharmony_ci		receive_dmsg(hc);
12168c2ecf20Sopenharmony_ci	if (val & 0x04) {	/* D tx */
12178c2ecf20Sopenharmony_ci		if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
12188c2ecf20Sopenharmony_ci			del_timer(&hc->dch.timer);
12198c2ecf20Sopenharmony_ci		tx_dirq(&hc->dch);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci	spin_unlock(&hc->lock);
12228c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
12238c2ecf20Sopenharmony_ci}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci/*
12268c2ecf20Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function
12278c2ecf20Sopenharmony_ci */
12288c2ecf20Sopenharmony_cistatic void
12298c2ecf20Sopenharmony_cihfcpci_dbusy_timer(struct timer_list *t)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci/*
12348c2ecf20Sopenharmony_ci * activate/deactivate hardware for selected channels and mode
12358c2ecf20Sopenharmony_ci */
12368c2ecf20Sopenharmony_cistatic int
12378c2ecf20Sopenharmony_cimode_hfcpci(struct bchannel *bch, int bc, int protocol)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
12408c2ecf20Sopenharmony_ci	int		fifo2;
12418c2ecf20Sopenharmony_ci	u_char		rx_slot = 0, tx_slot = 0, pcm_mode;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
12448c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
12458c2ecf20Sopenharmony_ci		       "HFCPCI bchannel protocol %x-->%x ch %x-->%x\n",
12468c2ecf20Sopenharmony_ci		       bch->state, protocol, bch->nr, bc);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	fifo2 = bc;
12498c2ecf20Sopenharmony_ci	pcm_mode = (bc >> 24) & 0xff;
12508c2ecf20Sopenharmony_ci	if (pcm_mode) { /* PCM SLOT USE */
12518c2ecf20Sopenharmony_ci		if (!test_bit(HFC_CFG_PCM, &hc->cfg))
12528c2ecf20Sopenharmony_ci			printk(KERN_WARNING
12538c2ecf20Sopenharmony_ci			       "%s: pcm channel id without HFC_CFG_PCM\n",
12548c2ecf20Sopenharmony_ci			       __func__);
12558c2ecf20Sopenharmony_ci		rx_slot = (bc >> 8) & 0xff;
12568c2ecf20Sopenharmony_ci		tx_slot = (bc >> 16) & 0xff;
12578c2ecf20Sopenharmony_ci		bc = bc & 0xff;
12588c2ecf20Sopenharmony_ci	} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE))
12598c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
12608c2ecf20Sopenharmony_ci		       __func__);
12618c2ecf20Sopenharmony_ci	if (hc->chanlimit > 1) {
12628c2ecf20Sopenharmony_ci		hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
12638c2ecf20Sopenharmony_ci		hc->hw.sctrl_e &= ~0x80;
12648c2ecf20Sopenharmony_ci	} else {
12658c2ecf20Sopenharmony_ci		if (bc & 2) {
12668c2ecf20Sopenharmony_ci			if (protocol != ISDN_P_NONE) {
12678c2ecf20Sopenharmony_ci				hc->hw.bswapped = 1; /* B1 and B2 exchanged */
12688c2ecf20Sopenharmony_ci				hc->hw.sctrl_e |= 0x80;
12698c2ecf20Sopenharmony_ci			} else {
12708c2ecf20Sopenharmony_ci				hc->hw.bswapped = 0; /* B1 and B2 normal mode */
12718c2ecf20Sopenharmony_ci				hc->hw.sctrl_e &= ~0x80;
12728c2ecf20Sopenharmony_ci			}
12738c2ecf20Sopenharmony_ci			fifo2 = 1;
12748c2ecf20Sopenharmony_ci		} else {
12758c2ecf20Sopenharmony_ci			hc->hw.bswapped = 0;	/* B1 and B2 normal mode */
12768c2ecf20Sopenharmony_ci			hc->hw.sctrl_e &= ~0x80;
12778c2ecf20Sopenharmony_ci		}
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci	switch (protocol) {
12808c2ecf20Sopenharmony_ci	case (-1): /* used for init */
12818c2ecf20Sopenharmony_ci		bch->state = -1;
12828c2ecf20Sopenharmony_ci		bch->nr = bc;
12838c2ecf20Sopenharmony_ci		fallthrough;
12848c2ecf20Sopenharmony_ci	case (ISDN_P_NONE):
12858c2ecf20Sopenharmony_ci		if (bch->state == ISDN_P_NONE)
12868c2ecf20Sopenharmony_ci			return 0;
12878c2ecf20Sopenharmony_ci		if (bc & 2) {
12888c2ecf20Sopenharmony_ci			hc->hw.sctrl &= ~SCTRL_B2_ENA;
12898c2ecf20Sopenharmony_ci			hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
12908c2ecf20Sopenharmony_ci		} else {
12918c2ecf20Sopenharmony_ci			hc->hw.sctrl &= ~SCTRL_B1_ENA;
12928c2ecf20Sopenharmony_ci			hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
12938c2ecf20Sopenharmony_ci		}
12948c2ecf20Sopenharmony_ci		if (fifo2 & 2) {
12958c2ecf20Sopenharmony_ci			hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
12968c2ecf20Sopenharmony_ci			hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS |
12978c2ecf20Sopenharmony_ci					   HFCPCI_INTS_B2REC);
12988c2ecf20Sopenharmony_ci		} else {
12998c2ecf20Sopenharmony_ci			hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
13008c2ecf20Sopenharmony_ci			hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS |
13018c2ecf20Sopenharmony_ci					   HFCPCI_INTS_B1REC);
13028c2ecf20Sopenharmony_ci		}
13038c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
13048c2ecf20Sopenharmony_ci		if (bch->nr & 2)
13058c2ecf20Sopenharmony_ci			hc->hw.cirm &= 0x7f;
13068c2ecf20Sopenharmony_ci		else
13078c2ecf20Sopenharmony_ci			hc->hw.cirm &= 0xbf;
13088c2ecf20Sopenharmony_ci#endif
13098c2ecf20Sopenharmony_ci		bch->state = ISDN_P_NONE;
13108c2ecf20Sopenharmony_ci		bch->nr = bc;
13118c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_HDLC, &bch->Flags);
13128c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
13138c2ecf20Sopenharmony_ci		break;
13148c2ecf20Sopenharmony_ci	case (ISDN_P_B_RAW):
13158c2ecf20Sopenharmony_ci		bch->state = protocol;
13168c2ecf20Sopenharmony_ci		bch->nr = bc;
13178c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
13188c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
13198c2ecf20Sopenharmony_ci		if (bc & 2) {
13208c2ecf20Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B2_ENA;
13218c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
13228c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
13238c2ecf20Sopenharmony_ci			hc->hw.cirm |= 0x80;
13248c2ecf20Sopenharmony_ci#endif
13258c2ecf20Sopenharmony_ci		} else {
13268c2ecf20Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B1_ENA;
13278c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
13288c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
13298c2ecf20Sopenharmony_ci			hc->hw.cirm |= 0x40;
13308c2ecf20Sopenharmony_ci#endif
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci		if (fifo2 & 2) {
13338c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
13348c2ecf20Sopenharmony_ci			if (!tics)
13358c2ecf20Sopenharmony_ci				hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
13368c2ecf20Sopenharmony_ci						  HFCPCI_INTS_B2REC);
13378c2ecf20Sopenharmony_ci			hc->hw.ctmt |= 2;
13388c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x18;
13398c2ecf20Sopenharmony_ci		} else {
13408c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
13418c2ecf20Sopenharmony_ci			if (!tics)
13428c2ecf20Sopenharmony_ci				hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
13438c2ecf20Sopenharmony_ci						  HFCPCI_INTS_B1REC);
13448c2ecf20Sopenharmony_ci			hc->hw.ctmt |= 1;
13458c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x03;
13468c2ecf20Sopenharmony_ci		}
13478c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
13488c2ecf20Sopenharmony_ci		break;
13498c2ecf20Sopenharmony_ci	case (ISDN_P_B_HDLC):
13508c2ecf20Sopenharmony_ci		bch->state = protocol;
13518c2ecf20Sopenharmony_ci		bch->nr = bc;
13528c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
13538c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
13548c2ecf20Sopenharmony_ci		if (bc & 2) {
13558c2ecf20Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B2_ENA;
13568c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
13578c2ecf20Sopenharmony_ci		} else {
13588c2ecf20Sopenharmony_ci			hc->hw.sctrl |= SCTRL_B1_ENA;
13598c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
13608c2ecf20Sopenharmony_ci		}
13618c2ecf20Sopenharmony_ci		if (fifo2 & 2) {
13628c2ecf20Sopenharmony_ci			hc->hw.last_bfifo_cnt[1] = 0;
13638c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
13648c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS |
13658c2ecf20Sopenharmony_ci					  HFCPCI_INTS_B2REC);
13668c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~2;
13678c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x18;
13688c2ecf20Sopenharmony_ci		} else {
13698c2ecf20Sopenharmony_ci			hc->hw.last_bfifo_cnt[0] = 0;
13708c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
13718c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS |
13728c2ecf20Sopenharmony_ci					  HFCPCI_INTS_B1REC);
13738c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~1;
13748c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x03;
13758c2ecf20Sopenharmony_ci		}
13768c2ecf20Sopenharmony_ci		test_and_set_bit(FLG_HDLC, &bch->Flags);
13778c2ecf20Sopenharmony_ci		break;
13788c2ecf20Sopenharmony_ci	default:
13798c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "prot not known %x\n", protocol);
13808c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci	if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
13838c2ecf20Sopenharmony_ci		if ((protocol == ISDN_P_NONE) ||
13848c2ecf20Sopenharmony_ci		    (protocol == -1)) {	/* init case */
13858c2ecf20Sopenharmony_ci			rx_slot = 0;
13868c2ecf20Sopenharmony_ci			tx_slot = 0;
13878c2ecf20Sopenharmony_ci		} else {
13888c2ecf20Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) {
13898c2ecf20Sopenharmony_ci				rx_slot |= 0xC0;
13908c2ecf20Sopenharmony_ci				tx_slot |= 0xC0;
13918c2ecf20Sopenharmony_ci			} else {
13928c2ecf20Sopenharmony_ci				rx_slot |= 0x80;
13938c2ecf20Sopenharmony_ci				tx_slot |= 0x80;
13948c2ecf20Sopenharmony_ci			}
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci		if (bc & 2) {
13978c2ecf20Sopenharmony_ci			hc->hw.conn &= 0xc7;
13988c2ecf20Sopenharmony_ci			hc->hw.conn |= 0x08;
13998c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_SSL 0x%x\n",
14008c2ecf20Sopenharmony_ci			       __func__, tx_slot);
14018c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_RSL 0x%x\n",
14028c2ecf20Sopenharmony_ci			       __func__, rx_slot);
14038c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
14048c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
14058c2ecf20Sopenharmony_ci		} else {
14068c2ecf20Sopenharmony_ci			hc->hw.conn &= 0xf8;
14078c2ecf20Sopenharmony_ci			hc->hw.conn |= 0x01;
14088c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_SSL 0x%x\n",
14098c2ecf20Sopenharmony_ci			       __func__, tx_slot);
14108c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_RSL 0x%x\n",
14118c2ecf20Sopenharmony_ci			       __func__, rx_slot);
14128c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
14138c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
14148c2ecf20Sopenharmony_ci		}
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
14178c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
14188c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
14198c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl);
14208c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
14218c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
14228c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
14238c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
14248c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
14258c2ecf20Sopenharmony_ci#endif
14268c2ecf20Sopenharmony_ci	return 0;
14278c2ecf20Sopenharmony_ci}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_cistatic int
14308c2ecf20Sopenharmony_ciset_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	if (bch->debug & DEBUG_HW_BCHANNEL)
14358c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
14368c2ecf20Sopenharmony_ci		       "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x\n",
14378c2ecf20Sopenharmony_ci		       bch->state, protocol, bch->nr, chan);
14388c2ecf20Sopenharmony_ci	if (bch->nr != chan) {
14398c2ecf20Sopenharmony_ci		printk(KERN_DEBUG
14408c2ecf20Sopenharmony_ci		       "HFCPCI rxtest wrong channel parameter %x/%x\n",
14418c2ecf20Sopenharmony_ci		       bch->nr, chan);
14428c2ecf20Sopenharmony_ci		return -EINVAL;
14438c2ecf20Sopenharmony_ci	}
14448c2ecf20Sopenharmony_ci	switch (protocol) {
14458c2ecf20Sopenharmony_ci	case (ISDN_P_B_RAW):
14468c2ecf20Sopenharmony_ci		bch->state = protocol;
14478c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
14488c2ecf20Sopenharmony_ci		if (chan & 2) {
14498c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
14508c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
14518c2ecf20Sopenharmony_ci			if (!tics)
14528c2ecf20Sopenharmony_ci				hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
14538c2ecf20Sopenharmony_ci			hc->hw.ctmt |= 2;
14548c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x18;
14558c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
14568c2ecf20Sopenharmony_ci			hc->hw.cirm |= 0x80;
14578c2ecf20Sopenharmony_ci#endif
14588c2ecf20Sopenharmony_ci		} else {
14598c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
14608c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
14618c2ecf20Sopenharmony_ci			if (!tics)
14628c2ecf20Sopenharmony_ci				hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
14638c2ecf20Sopenharmony_ci			hc->hw.ctmt |= 1;
14648c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x03;
14658c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
14668c2ecf20Sopenharmony_ci			hc->hw.cirm |= 0x40;
14678c2ecf20Sopenharmony_ci#endif
14688c2ecf20Sopenharmony_ci		}
14698c2ecf20Sopenharmony_ci		break;
14708c2ecf20Sopenharmony_ci	case (ISDN_P_B_HDLC):
14718c2ecf20Sopenharmony_ci		bch->state = protocol;
14728c2ecf20Sopenharmony_ci		hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
14738c2ecf20Sopenharmony_ci		if (chan & 2) {
14748c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B2_ENA;
14758c2ecf20Sopenharmony_ci			hc->hw.last_bfifo_cnt[1] = 0;
14768c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
14778c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
14788c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~2;
14798c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x18;
14808c2ecf20Sopenharmony_ci		} else {
14818c2ecf20Sopenharmony_ci			hc->hw.sctrl_r |= SCTRL_B1_ENA;
14828c2ecf20Sopenharmony_ci			hc->hw.last_bfifo_cnt[0] = 0;
14838c2ecf20Sopenharmony_ci			hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
14848c2ecf20Sopenharmony_ci			hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
14858c2ecf20Sopenharmony_ci			hc->hw.ctmt &= ~1;
14868c2ecf20Sopenharmony_ci			hc->hw.conn &= ~0x03;
14878c2ecf20Sopenharmony_ci		}
14888c2ecf20Sopenharmony_ci		break;
14898c2ecf20Sopenharmony_ci	default:
14908c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "prot not known %x\n", protocol);
14918c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
14948c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
14958c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r);
14968c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt);
14978c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
14988c2ecf20Sopenharmony_ci#ifdef REVERSE_BITORDER
14998c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
15008c2ecf20Sopenharmony_ci#endif
15018c2ecf20Sopenharmony_ci	return 0;
15028c2ecf20Sopenharmony_ci}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_cistatic void
15058c2ecf20Sopenharmony_cideactivate_bchannel(struct bchannel *bch)
15068c2ecf20Sopenharmony_ci{
15078c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
15088c2ecf20Sopenharmony_ci	u_long		flags;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
15118c2ecf20Sopenharmony_ci	mISDN_clear_bchannel(bch);
15128c2ecf20Sopenharmony_ci	mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
15138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
15148c2ecf20Sopenharmony_ci}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci/*
15178c2ecf20Sopenharmony_ci * Layer 1 B-channel hardware access
15188c2ecf20Sopenharmony_ci */
15198c2ecf20Sopenharmony_cistatic int
15208c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	return mISDN_ctrl_bchannel(bch, cq);
15238c2ecf20Sopenharmony_ci}
15248c2ecf20Sopenharmony_cistatic int
15258c2ecf20Sopenharmony_cihfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
15268c2ecf20Sopenharmony_ci{
15278c2ecf20Sopenharmony_ci	struct bchannel	*bch = container_of(ch, struct bchannel, ch);
15288c2ecf20Sopenharmony_ci	struct hfc_pci	*hc = bch->hw;
15298c2ecf20Sopenharmony_ci	int		ret = -EINVAL;
15308c2ecf20Sopenharmony_ci	u_long		flags;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (bch->debug & DEBUG_HW)
15338c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg);
15348c2ecf20Sopenharmony_ci	switch (cmd) {
15358c2ecf20Sopenharmony_ci	case HW_TESTRX_RAW:
15368c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
15378c2ecf20Sopenharmony_ci		ret = set_hfcpci_rxtest(bch, ISDN_P_B_RAW, (int)(long)arg);
15388c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
15398c2ecf20Sopenharmony_ci		break;
15408c2ecf20Sopenharmony_ci	case HW_TESTRX_HDLC:
15418c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
15428c2ecf20Sopenharmony_ci		ret = set_hfcpci_rxtest(bch, ISDN_P_B_HDLC, (int)(long)arg);
15438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
15448c2ecf20Sopenharmony_ci		break;
15458c2ecf20Sopenharmony_ci	case HW_TESTRX_OFF:
15468c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
15478c2ecf20Sopenharmony_ci		mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
15488c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
15498c2ecf20Sopenharmony_ci		ret = 0;
15508c2ecf20Sopenharmony_ci		break;
15518c2ecf20Sopenharmony_ci	case CLOSE_CHANNEL:
15528c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_OPEN, &bch->Flags);
15538c2ecf20Sopenharmony_ci		deactivate_bchannel(bch);
15548c2ecf20Sopenharmony_ci		ch->protocol = ISDN_P_NONE;
15558c2ecf20Sopenharmony_ci		ch->peer = NULL;
15568c2ecf20Sopenharmony_ci		module_put(THIS_MODULE);
15578c2ecf20Sopenharmony_ci		ret = 0;
15588c2ecf20Sopenharmony_ci		break;
15598c2ecf20Sopenharmony_ci	case CONTROL_CHANNEL:
15608c2ecf20Sopenharmony_ci		ret = channel_bctrl(bch, arg);
15618c2ecf20Sopenharmony_ci		break;
15628c2ecf20Sopenharmony_ci	default:
15638c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: unknown prim(%x)\n",
15648c2ecf20Sopenharmony_ci		       __func__, cmd);
15658c2ecf20Sopenharmony_ci	}
15668c2ecf20Sopenharmony_ci	return ret;
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci/*
15708c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Dchannel data
15718c2ecf20Sopenharmony_ci */
15728c2ecf20Sopenharmony_cistatic int
15738c2ecf20Sopenharmony_cihfcpci_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
15768c2ecf20Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
15778c2ecf20Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
15788c2ecf20Sopenharmony_ci	int			ret = -EINVAL;
15798c2ecf20Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
15808c2ecf20Sopenharmony_ci	unsigned int		id;
15818c2ecf20Sopenharmony_ci	u_long			flags;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	switch (hh->prim) {
15848c2ecf20Sopenharmony_ci	case PH_DATA_REQ:
15858c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
15868c2ecf20Sopenharmony_ci		ret = dchannel_senddata(dch, skb);
15878c2ecf20Sopenharmony_ci		if (ret > 0) { /* direct TX */
15888c2ecf20Sopenharmony_ci			id = hh->id; /* skb can be freed */
15898c2ecf20Sopenharmony_ci			hfcpci_fill_dfifo(dch->hw);
15908c2ecf20Sopenharmony_ci			ret = 0;
15918c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
15928c2ecf20Sopenharmony_ci			queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
15938c2ecf20Sopenharmony_ci		} else
15948c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
15958c2ecf20Sopenharmony_ci		return ret;
15968c2ecf20Sopenharmony_ci	case PH_ACTIVATE_REQ:
15978c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
15988c2ecf20Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
15998c2ecf20Sopenharmony_ci			ret = 0;
16008c2ecf20Sopenharmony_ci			if (test_bit(HFC_CFG_MASTER, &hc->cfg))
16018c2ecf20Sopenharmony_ci				hc->hw.mst_m |= HFCPCI_MASTER;
16028c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
16038c2ecf20Sopenharmony_ci			if (test_bit(FLG_ACTIVE, &dch->Flags)) {
16048c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&hc->lock, flags);
16058c2ecf20Sopenharmony_ci				_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
16068c2ecf20Sopenharmony_ci					    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
16078c2ecf20Sopenharmony_ci				break;
16088c2ecf20Sopenharmony_ci			}
16098c2ecf20Sopenharmony_ci			test_and_set_bit(FLG_L2_ACTIVATED, &dch->Flags);
16108c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE |
16118c2ecf20Sopenharmony_ci				  HFCPCI_DO_ACTION | 1);
16128c2ecf20Sopenharmony_ci		} else
16138c2ecf20Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
16148c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
16158c2ecf20Sopenharmony_ci		break;
16168c2ecf20Sopenharmony_ci	case PH_DEACTIVATE_REQ:
16178c2ecf20Sopenharmony_ci		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
16188c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
16198c2ecf20Sopenharmony_ci		if (hc->hw.protocol == ISDN_P_NT_S0) {
16208c2ecf20Sopenharmony_ci			struct sk_buff_head free_queue;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci			__skb_queue_head_init(&free_queue);
16238c2ecf20Sopenharmony_ci			/* prepare deactivation */
16248c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_STATES, 0x40);
16258c2ecf20Sopenharmony_ci			skb_queue_splice_init(&dch->squeue, &free_queue);
16268c2ecf20Sopenharmony_ci			if (dch->tx_skb) {
16278c2ecf20Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->tx_skb);
16288c2ecf20Sopenharmony_ci				dch->tx_skb = NULL;
16298c2ecf20Sopenharmony_ci			}
16308c2ecf20Sopenharmony_ci			dch->tx_idx = 0;
16318c2ecf20Sopenharmony_ci			if (dch->rx_skb) {
16328c2ecf20Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->rx_skb);
16338c2ecf20Sopenharmony_ci				dch->rx_skb = NULL;
16348c2ecf20Sopenharmony_ci			}
16358c2ecf20Sopenharmony_ci			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
16368c2ecf20Sopenharmony_ci			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
16378c2ecf20Sopenharmony_ci				del_timer(&dch->timer);
16388c2ecf20Sopenharmony_ci#ifdef FIXME
16398c2ecf20Sopenharmony_ci			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
16408c2ecf20Sopenharmony_ci				dchannel_sched_event(&hc->dch, D_CLEARBUSY);
16418c2ecf20Sopenharmony_ci#endif
16428c2ecf20Sopenharmony_ci			hc->hw.mst_m &= ~HFCPCI_MASTER;
16438c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
16448c2ecf20Sopenharmony_ci			ret = 0;
16458c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
16468c2ecf20Sopenharmony_ci			__skb_queue_purge(&free_queue);
16478c2ecf20Sopenharmony_ci		} else {
16488c2ecf20Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
16498c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
16508c2ecf20Sopenharmony_ci		}
16518c2ecf20Sopenharmony_ci		break;
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci	if (!ret)
16548c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
16558c2ecf20Sopenharmony_ci	return ret;
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci/*
16598c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Bchannel data
16608c2ecf20Sopenharmony_ci */
16618c2ecf20Sopenharmony_cistatic int
16628c2ecf20Sopenharmony_cihfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	struct bchannel		*bch = container_of(ch, struct bchannel, ch);
16658c2ecf20Sopenharmony_ci	struct hfc_pci		*hc = bch->hw;
16668c2ecf20Sopenharmony_ci	int			ret = -EINVAL;
16678c2ecf20Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
16688c2ecf20Sopenharmony_ci	unsigned long		flags;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	switch (hh->prim) {
16718c2ecf20Sopenharmony_ci	case PH_DATA_REQ:
16728c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
16738c2ecf20Sopenharmony_ci		ret = bchannel_senddata(bch, skb);
16748c2ecf20Sopenharmony_ci		if (ret > 0) { /* direct TX */
16758c2ecf20Sopenharmony_ci			hfcpci_fill_fifo(bch);
16768c2ecf20Sopenharmony_ci			ret = 0;
16778c2ecf20Sopenharmony_ci		}
16788c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
16798c2ecf20Sopenharmony_ci		return ret;
16808c2ecf20Sopenharmony_ci	case PH_ACTIVATE_REQ:
16818c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
16828c2ecf20Sopenharmony_ci		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
16838c2ecf20Sopenharmony_ci			ret = mode_hfcpci(bch, bch->nr, ch->protocol);
16848c2ecf20Sopenharmony_ci		else
16858c2ecf20Sopenharmony_ci			ret = 0;
16868c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
16878c2ecf20Sopenharmony_ci		if (!ret)
16888c2ecf20Sopenharmony_ci			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
16898c2ecf20Sopenharmony_ci				    NULL, GFP_KERNEL);
16908c2ecf20Sopenharmony_ci		break;
16918c2ecf20Sopenharmony_ci	case PH_DEACTIVATE_REQ:
16928c2ecf20Sopenharmony_ci		deactivate_bchannel(bch);
16938c2ecf20Sopenharmony_ci		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
16948c2ecf20Sopenharmony_ci			    NULL, GFP_KERNEL);
16958c2ecf20Sopenharmony_ci		ret = 0;
16968c2ecf20Sopenharmony_ci		break;
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci	if (!ret)
16998c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
17008c2ecf20Sopenharmony_ci	return ret;
17018c2ecf20Sopenharmony_ci}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci/*
17048c2ecf20Sopenharmony_ci * called for card init message
17058c2ecf20Sopenharmony_ci */
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic void
17088c2ecf20Sopenharmony_ciinithfcpci(struct hfc_pci *hc)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "inithfcpci: entered\n");
17118c2ecf20Sopenharmony_ci	timer_setup(&hc->dch.timer, hfcpci_dbusy_timer, 0);
17128c2ecf20Sopenharmony_ci	hc->chanlimit = 2;
17138c2ecf20Sopenharmony_ci	mode_hfcpci(&hc->bch[0], 1, -1);
17148c2ecf20Sopenharmony_ci	mode_hfcpci(&hc->bch[1], 2, -1);
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic int
17198c2ecf20Sopenharmony_ciinit_card(struct hfc_pci *hc)
17208c2ecf20Sopenharmony_ci{
17218c2ecf20Sopenharmony_ci	int	cnt = 3;
17228c2ecf20Sopenharmony_ci	u_long	flags;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "init_card: entered\n");
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
17288c2ecf20Sopenharmony_ci	disable_hwirq(hc);
17298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
17308c2ecf20Sopenharmony_ci	if (request_irq(hc->irq, hfcpci_int, IRQF_SHARED, "HFC PCI", hc)) {
17318c2ecf20Sopenharmony_ci		printk(KERN_WARNING
17328c2ecf20Sopenharmony_ci		       "mISDN: couldn't get interrupt %d\n", hc->irq);
17338c2ecf20Sopenharmony_ci		return -EIO;
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
17368c2ecf20Sopenharmony_ci	reset_hfcpci(hc);
17378c2ecf20Sopenharmony_ci	while (cnt) {
17388c2ecf20Sopenharmony_ci		inithfcpci(hc);
17398c2ecf20Sopenharmony_ci		/*
17408c2ecf20Sopenharmony_ci		 * Finally enable IRQ output
17418c2ecf20Sopenharmony_ci		 * this is only allowed, if an IRQ routine is already
17428c2ecf20Sopenharmony_ci		 * established for this HFC, so don't do that earlier
17438c2ecf20Sopenharmony_ci		 */
17448c2ecf20Sopenharmony_ci		enable_hwirq(hc);
17458c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
17468c2ecf20Sopenharmony_ci		/* Timeout 80ms */
17478c2ecf20Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
17488c2ecf20Sopenharmony_ci		schedule_timeout((80 * HZ) / 1000);
17498c2ecf20Sopenharmony_ci		printk(KERN_INFO "HFC PCI: IRQ %d count %d\n",
17508c2ecf20Sopenharmony_ci		       hc->irq, hc->irqcnt);
17518c2ecf20Sopenharmony_ci		/* now switch timer interrupt off */
17528c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
17538c2ecf20Sopenharmony_ci		hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
17548c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
17558c2ecf20Sopenharmony_ci		/* reinit mode reg */
17568c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
17578c2ecf20Sopenharmony_ci		if (!hc->irqcnt) {
17588c2ecf20Sopenharmony_ci			printk(KERN_WARNING
17598c2ecf20Sopenharmony_ci			       "HFC PCI: IRQ(%d) getting no interrupts "
17608c2ecf20Sopenharmony_ci			       "during init %d\n", hc->irq, 4 - cnt);
17618c2ecf20Sopenharmony_ci			if (cnt == 1)
17628c2ecf20Sopenharmony_ci				break;
17638c2ecf20Sopenharmony_ci			else {
17648c2ecf20Sopenharmony_ci				reset_hfcpci(hc);
17658c2ecf20Sopenharmony_ci				cnt--;
17668c2ecf20Sopenharmony_ci			}
17678c2ecf20Sopenharmony_ci		} else {
17688c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
17698c2ecf20Sopenharmony_ci			hc->initdone = 1;
17708c2ecf20Sopenharmony_ci			return 0;
17718c2ecf20Sopenharmony_ci		}
17728c2ecf20Sopenharmony_ci	}
17738c2ecf20Sopenharmony_ci	disable_hwirq(hc);
17748c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
17758c2ecf20Sopenharmony_ci	free_irq(hc->irq, hc);
17768c2ecf20Sopenharmony_ci	return -EIO;
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_cistatic int
17808c2ecf20Sopenharmony_cichannel_ctrl(struct hfc_pci *hc, struct mISDN_ctrl_req *cq)
17818c2ecf20Sopenharmony_ci{
17828c2ecf20Sopenharmony_ci	int	ret = 0;
17838c2ecf20Sopenharmony_ci	u_char	slot;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	switch (cq->op) {
17868c2ecf20Sopenharmony_ci	case MISDN_CTRL_GETOP:
17878c2ecf20Sopenharmony_ci		cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
17888c2ecf20Sopenharmony_ci			 MISDN_CTRL_DISCONNECT | MISDN_CTRL_L1_TIMER3;
17898c2ecf20Sopenharmony_ci		break;
17908c2ecf20Sopenharmony_ci	case MISDN_CTRL_LOOP:
17918c2ecf20Sopenharmony_ci		/* channel 0 disabled loop */
17928c2ecf20Sopenharmony_ci		if (cq->channel < 0 || cq->channel > 2) {
17938c2ecf20Sopenharmony_ci			ret = -EINVAL;
17948c2ecf20Sopenharmony_ci			break;
17958c2ecf20Sopenharmony_ci		}
17968c2ecf20Sopenharmony_ci		if (cq->channel & 1) {
17978c2ecf20Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
17988c2ecf20Sopenharmony_ci				slot = 0xC0;
17998c2ecf20Sopenharmony_ci			else
18008c2ecf20Sopenharmony_ci				slot = 0x80;
18018c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
18028c2ecf20Sopenharmony_ci			       __func__, slot);
18038c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_SSL, slot);
18048c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B1_RSL, slot);
18058c2ecf20Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~7) | 6;
18068c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
18078c2ecf20Sopenharmony_ci		}
18088c2ecf20Sopenharmony_ci		if (cq->channel & 2) {
18098c2ecf20Sopenharmony_ci			if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
18108c2ecf20Sopenharmony_ci				slot = 0xC1;
18118c2ecf20Sopenharmony_ci			else
18128c2ecf20Sopenharmony_ci				slot = 0x81;
18138c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
18148c2ecf20Sopenharmony_ci			       __func__, slot);
18158c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_SSL, slot);
18168c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_B2_RSL, slot);
18178c2ecf20Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~0x38) | 0x30;
18188c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
18198c2ecf20Sopenharmony_ci		}
18208c2ecf20Sopenharmony_ci		if (cq->channel & 3)
18218c2ecf20Sopenharmony_ci			hc->hw.trm |= 0x80;	/* enable IOM-loop */
18228c2ecf20Sopenharmony_ci		else {
18238c2ecf20Sopenharmony_ci			hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
18248c2ecf20Sopenharmony_ci			Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
18258c2ecf20Sopenharmony_ci			hc->hw.trm &= 0x7f;	/* disable IOM-loop */
18268c2ecf20Sopenharmony_ci		}
18278c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
18288c2ecf20Sopenharmony_ci		break;
18298c2ecf20Sopenharmony_ci	case MISDN_CTRL_CONNECT:
18308c2ecf20Sopenharmony_ci		if (cq->channel == cq->p1) {
18318c2ecf20Sopenharmony_ci			ret = -EINVAL;
18328c2ecf20Sopenharmony_ci			break;
18338c2ecf20Sopenharmony_ci		}
18348c2ecf20Sopenharmony_ci		if (cq->channel < 1 || cq->channel > 2 ||
18358c2ecf20Sopenharmony_ci		    cq->p1 < 1 || cq->p1 > 2) {
18368c2ecf20Sopenharmony_ci			ret = -EINVAL;
18378c2ecf20Sopenharmony_ci			break;
18388c2ecf20Sopenharmony_ci		}
18398c2ecf20Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
18408c2ecf20Sopenharmony_ci			slot = 0xC0;
18418c2ecf20Sopenharmony_ci		else
18428c2ecf20Sopenharmony_ci			slot = 0x80;
18438c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n",
18448c2ecf20Sopenharmony_ci		       __func__, slot);
18458c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_B1_SSL, slot);
18468c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_B2_RSL, slot);
18478c2ecf20Sopenharmony_ci		if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
18488c2ecf20Sopenharmony_ci			slot = 0xC1;
18498c2ecf20Sopenharmony_ci		else
18508c2ecf20Sopenharmony_ci			slot = 0x81;
18518c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n",
18528c2ecf20Sopenharmony_ci		       __func__, slot);
18538c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_B2_SSL, slot);
18548c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_B1_RSL, slot);
18558c2ecf20Sopenharmony_ci		hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x36;
18568c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
18578c2ecf20Sopenharmony_ci		hc->hw.trm |= 0x80;
18588c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_TRM, hc->hw.trm);
18598c2ecf20Sopenharmony_ci		break;
18608c2ecf20Sopenharmony_ci	case MISDN_CTRL_DISCONNECT:
18618c2ecf20Sopenharmony_ci		hc->hw.conn = (hc->hw.conn & ~0x3f) | 0x09;
18628c2ecf20Sopenharmony_ci		Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
18638c2ecf20Sopenharmony_ci		hc->hw.trm &= 0x7f;	/* disable IOM-loop */
18648c2ecf20Sopenharmony_ci		break;
18658c2ecf20Sopenharmony_ci	case MISDN_CTRL_L1_TIMER3:
18668c2ecf20Sopenharmony_ci		ret = l1_event(hc->dch.l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
18678c2ecf20Sopenharmony_ci		break;
18688c2ecf20Sopenharmony_ci	default:
18698c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: unknown Op %x\n",
18708c2ecf20Sopenharmony_ci		       __func__, cq->op);
18718c2ecf20Sopenharmony_ci		ret = -EINVAL;
18728c2ecf20Sopenharmony_ci		break;
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci	return ret;
18758c2ecf20Sopenharmony_ci}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cistatic int
18788c2ecf20Sopenharmony_ciopen_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch,
18798c2ecf20Sopenharmony_ci	      struct channel_req *rq)
18808c2ecf20Sopenharmony_ci{
18818c2ecf20Sopenharmony_ci	int err = 0;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	if (debug & DEBUG_HW_OPEN)
18848c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
18858c2ecf20Sopenharmony_ci		       hc->dch.dev.id, __builtin_return_address(0));
18868c2ecf20Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
18878c2ecf20Sopenharmony_ci		return -EINVAL;
18888c2ecf20Sopenharmony_ci	if (rq->adr.channel == 1) {
18898c2ecf20Sopenharmony_ci		/* TODO: E-Channel */
18908c2ecf20Sopenharmony_ci		return -EINVAL;
18918c2ecf20Sopenharmony_ci	}
18928c2ecf20Sopenharmony_ci	if (!hc->initdone) {
18938c2ecf20Sopenharmony_ci		if (rq->protocol == ISDN_P_TE_S0) {
18948c2ecf20Sopenharmony_ci			err = create_l1(&hc->dch, hfc_l1callback);
18958c2ecf20Sopenharmony_ci			if (err)
18968c2ecf20Sopenharmony_ci				return err;
18978c2ecf20Sopenharmony_ci		}
18988c2ecf20Sopenharmony_ci		hc->hw.protocol = rq->protocol;
18998c2ecf20Sopenharmony_ci		ch->protocol = rq->protocol;
19008c2ecf20Sopenharmony_ci		err = init_card(hc);
19018c2ecf20Sopenharmony_ci		if (err)
19028c2ecf20Sopenharmony_ci			return err;
19038c2ecf20Sopenharmony_ci	} else {
19048c2ecf20Sopenharmony_ci		if (rq->protocol != ch->protocol) {
19058c2ecf20Sopenharmony_ci			if (hc->hw.protocol == ISDN_P_TE_S0)
19068c2ecf20Sopenharmony_ci				l1_event(hc->dch.l1, CLOSE_CHANNEL);
19078c2ecf20Sopenharmony_ci			if (rq->protocol == ISDN_P_TE_S0) {
19088c2ecf20Sopenharmony_ci				err = create_l1(&hc->dch, hfc_l1callback);
19098c2ecf20Sopenharmony_ci				if (err)
19108c2ecf20Sopenharmony_ci					return err;
19118c2ecf20Sopenharmony_ci			}
19128c2ecf20Sopenharmony_ci			hc->hw.protocol = rq->protocol;
19138c2ecf20Sopenharmony_ci			ch->protocol = rq->protocol;
19148c2ecf20Sopenharmony_ci			hfcpci_setmode(hc);
19158c2ecf20Sopenharmony_ci		}
19168c2ecf20Sopenharmony_ci	}
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	if (((ch->protocol == ISDN_P_NT_S0) && (hc->dch.state == 3)) ||
19198c2ecf20Sopenharmony_ci	    ((ch->protocol == ISDN_P_TE_S0) && (hc->dch.state == 7))) {
19208c2ecf20Sopenharmony_ci		_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
19218c2ecf20Sopenharmony_ci			    0, NULL, GFP_KERNEL);
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci	rq->ch = ch;
19248c2ecf20Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
19258c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
19268c2ecf20Sopenharmony_ci	return 0;
19278c2ecf20Sopenharmony_ci}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_cistatic int
19308c2ecf20Sopenharmony_ciopen_bchannel(struct hfc_pci *hc, struct channel_req *rq)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	struct bchannel		*bch;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	if (rq->adr.channel == 0 || rq->adr.channel > 2)
19358c2ecf20Sopenharmony_ci		return -EINVAL;
19368c2ecf20Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
19378c2ecf20Sopenharmony_ci		return -EINVAL;
19388c2ecf20Sopenharmony_ci	bch = &hc->bch[rq->adr.channel - 1];
19398c2ecf20Sopenharmony_ci	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
19408c2ecf20Sopenharmony_ci		return -EBUSY; /* b-channel can be only open once */
19418c2ecf20Sopenharmony_ci	bch->ch.protocol = rq->protocol;
19428c2ecf20Sopenharmony_ci	rq->ch = &bch->ch; /* TODO: E-channel */
19438c2ecf20Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
19448c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
19458c2ecf20Sopenharmony_ci	return 0;
19468c2ecf20Sopenharmony_ci}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci/*
19498c2ecf20Sopenharmony_ci * device control function
19508c2ecf20Sopenharmony_ci */
19518c2ecf20Sopenharmony_cistatic int
19528c2ecf20Sopenharmony_cihfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
19538c2ecf20Sopenharmony_ci{
19548c2ecf20Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
19558c2ecf20Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
19568c2ecf20Sopenharmony_ci	struct hfc_pci		*hc = dch->hw;
19578c2ecf20Sopenharmony_ci	struct channel_req	*rq;
19588c2ecf20Sopenharmony_ci	int			err = 0;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	if (dch->debug & DEBUG_HW)
19618c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n",
19628c2ecf20Sopenharmony_ci		       __func__, cmd, arg);
19638c2ecf20Sopenharmony_ci	switch (cmd) {
19648c2ecf20Sopenharmony_ci	case OPEN_CHANNEL:
19658c2ecf20Sopenharmony_ci		rq = arg;
19668c2ecf20Sopenharmony_ci		if ((rq->protocol == ISDN_P_TE_S0) ||
19678c2ecf20Sopenharmony_ci		    (rq->protocol == ISDN_P_NT_S0))
19688c2ecf20Sopenharmony_ci			err = open_dchannel(hc, ch, rq);
19698c2ecf20Sopenharmony_ci		else
19708c2ecf20Sopenharmony_ci			err = open_bchannel(hc, rq);
19718c2ecf20Sopenharmony_ci		break;
19728c2ecf20Sopenharmony_ci	case CLOSE_CHANNEL:
19738c2ecf20Sopenharmony_ci		if (debug & DEBUG_HW_OPEN)
19748c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
19758c2ecf20Sopenharmony_ci			       __func__, hc->dch.dev.id,
19768c2ecf20Sopenharmony_ci			       __builtin_return_address(0));
19778c2ecf20Sopenharmony_ci		module_put(THIS_MODULE);
19788c2ecf20Sopenharmony_ci		break;
19798c2ecf20Sopenharmony_ci	case CONTROL_CHANNEL:
19808c2ecf20Sopenharmony_ci		err = channel_ctrl(hc, arg);
19818c2ecf20Sopenharmony_ci		break;
19828c2ecf20Sopenharmony_ci	default:
19838c2ecf20Sopenharmony_ci		if (dch->debug & DEBUG_HW)
19848c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
19858c2ecf20Sopenharmony_ci			       __func__, cmd);
19868c2ecf20Sopenharmony_ci		return -EINVAL;
19878c2ecf20Sopenharmony_ci	}
19888c2ecf20Sopenharmony_ci	return err;
19898c2ecf20Sopenharmony_ci}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_cistatic int
19928c2ecf20Sopenharmony_cisetup_hw(struct hfc_pci *hc)
19938c2ecf20Sopenharmony_ci{
19948c2ecf20Sopenharmony_ci	void	*buffer;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	printk(KERN_INFO "mISDN: HFC-PCI driver %s\n", hfcpci_revision);
19978c2ecf20Sopenharmony_ci	hc->hw.cirm = 0;
19988c2ecf20Sopenharmony_ci	hc->dch.state = 0;
19998c2ecf20Sopenharmony_ci	pci_set_master(hc->pdev);
20008c2ecf20Sopenharmony_ci	if (!hc->irq) {
20018c2ecf20Sopenharmony_ci		printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
20028c2ecf20Sopenharmony_ci		return -EINVAL;
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ci	hc->hw.pci_io =
20058c2ecf20Sopenharmony_ci		(char __iomem *)(unsigned long)hc->pdev->resource[1].start;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	if (!hc->hw.pci_io) {
20088c2ecf20Sopenharmony_ci		printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
20098c2ecf20Sopenharmony_ci		return -ENOMEM;
20108c2ecf20Sopenharmony_ci	}
20118c2ecf20Sopenharmony_ci	/* Allocate memory for FIFOS */
20128c2ecf20Sopenharmony_ci	/* the memory needs to be on a 32k boundary within the first 4G */
20138c2ecf20Sopenharmony_ci	if (dma_set_mask(&hc->pdev->dev, 0xFFFF8000)) {
20148c2ecf20Sopenharmony_ci		printk(KERN_WARNING
20158c2ecf20Sopenharmony_ci		       "HFC-PCI: No usable DMA configuration!\n");
20168c2ecf20Sopenharmony_ci		return -EIO;
20178c2ecf20Sopenharmony_ci	}
20188c2ecf20Sopenharmony_ci	buffer = dma_alloc_coherent(&hc->pdev->dev, 0x8000, &hc->hw.dmahandle,
20198c2ecf20Sopenharmony_ci				    GFP_KERNEL);
20208c2ecf20Sopenharmony_ci	/* We silently assume the address is okay if nonzero */
20218c2ecf20Sopenharmony_ci	if (!buffer) {
20228c2ecf20Sopenharmony_ci		printk(KERN_WARNING
20238c2ecf20Sopenharmony_ci		       "HFC-PCI: Error allocating memory for FIFO!\n");
20248c2ecf20Sopenharmony_ci		return -ENOMEM;
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci	hc->hw.fifos = buffer;
20278c2ecf20Sopenharmony_ci	pci_write_config_dword(hc->pdev, 0x80, hc->hw.dmahandle);
20288c2ecf20Sopenharmony_ci	hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256);
20298c2ecf20Sopenharmony_ci	if (unlikely(!hc->hw.pci_io)) {
20308c2ecf20Sopenharmony_ci		printk(KERN_WARNING
20318c2ecf20Sopenharmony_ci		       "HFC-PCI: Error in ioremap for PCI!\n");
20328c2ecf20Sopenharmony_ci		dma_free_coherent(&hc->pdev->dev, 0x8000, hc->hw.fifos,
20338c2ecf20Sopenharmony_ci				  hc->hw.dmahandle);
20348c2ecf20Sopenharmony_ci		return -ENOMEM;
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	printk(KERN_INFO
20388c2ecf20Sopenharmony_ci	       "HFC-PCI: defined at mem %#lx fifo %p(%pad) IRQ %d HZ %d\n",
20398c2ecf20Sopenharmony_ci	       (u_long) hc->hw.pci_io, hc->hw.fifos,
20408c2ecf20Sopenharmony_ci	       &hc->hw.dmahandle, hc->irq, HZ);
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/* enable memory mapped ports, disable busmaster */
20438c2ecf20Sopenharmony_ci	pci_write_config_word(hc->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
20448c2ecf20Sopenharmony_ci	hc->hw.int_m2 = 0;
20458c2ecf20Sopenharmony_ci	disable_hwirq(hc);
20468c2ecf20Sopenharmony_ci	hc->hw.int_m1 = 0;
20478c2ecf20Sopenharmony_ci	Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
20488c2ecf20Sopenharmony_ci	/* At this point the needed PCI config is done */
20498c2ecf20Sopenharmony_ci	/* fifos are still not enabled */
20508c2ecf20Sopenharmony_ci	timer_setup(&hc->hw.timer, hfcpci_Timer, 0);
20518c2ecf20Sopenharmony_ci	/* default PCM master */
20528c2ecf20Sopenharmony_ci	test_and_set_bit(HFC_CFG_MASTER, &hc->cfg);
20538c2ecf20Sopenharmony_ci	return 0;
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cistatic void
20578c2ecf20Sopenharmony_cirelease_card(struct hfc_pci *hc) {
20588c2ecf20Sopenharmony_ci	u_long	flags;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
20618c2ecf20Sopenharmony_ci	hc->hw.int_m2 = 0; /* interrupt output off ! */
20628c2ecf20Sopenharmony_ci	disable_hwirq(hc);
20638c2ecf20Sopenharmony_ci	mode_hfcpci(&hc->bch[0], 1, ISDN_P_NONE);
20648c2ecf20Sopenharmony_ci	mode_hfcpci(&hc->bch[1], 2, ISDN_P_NONE);
20658c2ecf20Sopenharmony_ci	if (hc->dch.timer.function != NULL) {
20668c2ecf20Sopenharmony_ci		del_timer(&hc->dch.timer);
20678c2ecf20Sopenharmony_ci		hc->dch.timer.function = NULL;
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
20708c2ecf20Sopenharmony_ci	if (hc->hw.protocol == ISDN_P_TE_S0)
20718c2ecf20Sopenharmony_ci		l1_event(hc->dch.l1, CLOSE_CHANNEL);
20728c2ecf20Sopenharmony_ci	if (hc->initdone)
20738c2ecf20Sopenharmony_ci		free_irq(hc->irq, hc);
20748c2ecf20Sopenharmony_ci	release_io_hfcpci(hc); /* must release after free_irq! */
20758c2ecf20Sopenharmony_ci	mISDN_unregister_device(&hc->dch.dev);
20768c2ecf20Sopenharmony_ci	mISDN_freebchannel(&hc->bch[1]);
20778c2ecf20Sopenharmony_ci	mISDN_freebchannel(&hc->bch[0]);
20788c2ecf20Sopenharmony_ci	mISDN_freedchannel(&hc->dch);
20798c2ecf20Sopenharmony_ci	pci_set_drvdata(hc->pdev, NULL);
20808c2ecf20Sopenharmony_ci	kfree(hc);
20818c2ecf20Sopenharmony_ci}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_cistatic int
20848c2ecf20Sopenharmony_cisetup_card(struct hfc_pci *card)
20858c2ecf20Sopenharmony_ci{
20868c2ecf20Sopenharmony_ci	int		err = -EINVAL;
20878c2ecf20Sopenharmony_ci	u_int		i;
20888c2ecf20Sopenharmony_ci	char		name[MISDN_MAX_IDLEN];
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	card->dch.debug = debug;
20918c2ecf20Sopenharmony_ci	spin_lock_init(&card->lock);
20928c2ecf20Sopenharmony_ci	mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state);
20938c2ecf20Sopenharmony_ci	card->dch.hw = card;
20948c2ecf20Sopenharmony_ci	card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
20958c2ecf20Sopenharmony_ci	card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
20968c2ecf20Sopenharmony_ci		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
20978c2ecf20Sopenharmony_ci	card->dch.dev.D.send = hfcpci_l2l1D;
20988c2ecf20Sopenharmony_ci	card->dch.dev.D.ctrl = hfc_dctrl;
20998c2ecf20Sopenharmony_ci	card->dch.dev.nrbchan = 2;
21008c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
21018c2ecf20Sopenharmony_ci		card->bch[i].nr = i + 1;
21028c2ecf20Sopenharmony_ci		set_channelmap(i + 1, card->dch.dev.channelmap);
21038c2ecf20Sopenharmony_ci		card->bch[i].debug = debug;
21048c2ecf20Sopenharmony_ci		mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1);
21058c2ecf20Sopenharmony_ci		card->bch[i].hw = card;
21068c2ecf20Sopenharmony_ci		card->bch[i].ch.send = hfcpci_l2l1B;
21078c2ecf20Sopenharmony_ci		card->bch[i].ch.ctrl = hfc_bctrl;
21088c2ecf20Sopenharmony_ci		card->bch[i].ch.nr = i + 1;
21098c2ecf20Sopenharmony_ci		list_add(&card->bch[i].ch.list, &card->dch.dev.bchannels);
21108c2ecf20Sopenharmony_ci	}
21118c2ecf20Sopenharmony_ci	err = setup_hw(card);
21128c2ecf20Sopenharmony_ci	if (err)
21138c2ecf20Sopenharmony_ci		goto error;
21148c2ecf20Sopenharmony_ci	snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1);
21158c2ecf20Sopenharmony_ci	err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name);
21168c2ecf20Sopenharmony_ci	if (err)
21178c2ecf20Sopenharmony_ci		goto error;
21188c2ecf20Sopenharmony_ci	HFC_cnt++;
21198c2ecf20Sopenharmony_ci	printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
21208c2ecf20Sopenharmony_ci	return 0;
21218c2ecf20Sopenharmony_cierror:
21228c2ecf20Sopenharmony_ci	mISDN_freebchannel(&card->bch[1]);
21238c2ecf20Sopenharmony_ci	mISDN_freebchannel(&card->bch[0]);
21248c2ecf20Sopenharmony_ci	mISDN_freedchannel(&card->dch);
21258c2ecf20Sopenharmony_ci	kfree(card);
21268c2ecf20Sopenharmony_ci	return err;
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci/* private data in the PCI devices list */
21308c2ecf20Sopenharmony_cistruct _hfc_map {
21318c2ecf20Sopenharmony_ci	u_int	subtype;
21328c2ecf20Sopenharmony_ci	u_int	flag;
21338c2ecf20Sopenharmony_ci	char	*name;
21348c2ecf20Sopenharmony_ci};
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_cistatic const struct _hfc_map hfc_map[] =
21378c2ecf20Sopenharmony_ci{
21388c2ecf20Sopenharmony_ci	{HFC_CCD_2BD0, 0, "CCD/Billion/Asuscom 2BD0"},
21398c2ecf20Sopenharmony_ci	{HFC_CCD_B000, 0, "Billion B000"},
21408c2ecf20Sopenharmony_ci	{HFC_CCD_B006, 0, "Billion B006"},
21418c2ecf20Sopenharmony_ci	{HFC_CCD_B007, 0, "Billion B007"},
21428c2ecf20Sopenharmony_ci	{HFC_CCD_B008, 0, "Billion B008"},
21438c2ecf20Sopenharmony_ci	{HFC_CCD_B009, 0, "Billion B009"},
21448c2ecf20Sopenharmony_ci	{HFC_CCD_B00A, 0, "Billion B00A"},
21458c2ecf20Sopenharmony_ci	{HFC_CCD_B00B, 0, "Billion B00B"},
21468c2ecf20Sopenharmony_ci	{HFC_CCD_B00C, 0, "Billion B00C"},
21478c2ecf20Sopenharmony_ci	{HFC_CCD_B100, 0, "Seyeon B100"},
21488c2ecf20Sopenharmony_ci	{HFC_CCD_B700, 0, "Primux II S0 B700"},
21498c2ecf20Sopenharmony_ci	{HFC_CCD_B701, 0, "Primux II S0 NT B701"},
21508c2ecf20Sopenharmony_ci	{HFC_ABOCOM_2BD1, 0, "Abocom/Magitek 2BD1"},
21518c2ecf20Sopenharmony_ci	{HFC_ASUS_0675, 0, "Asuscom/Askey 675"},
21528c2ecf20Sopenharmony_ci	{HFC_BERKOM_TCONCEPT, 0, "German telekom T-Concept"},
21538c2ecf20Sopenharmony_ci	{HFC_BERKOM_A1T, 0, "German telekom A1T"},
21548c2ecf20Sopenharmony_ci	{HFC_ANIGMA_MC145575, 0, "Motorola MC145575"},
21558c2ecf20Sopenharmony_ci	{HFC_ZOLTRIX_2BD0, 0, "Zoltrix 2BD0"},
21568c2ecf20Sopenharmony_ci	{HFC_DIGI_DF_M_IOM2_E, 0,
21578c2ecf20Sopenharmony_ci	 "Digi International DataFire Micro V IOM2 (Europe)"},
21588c2ecf20Sopenharmony_ci	{HFC_DIGI_DF_M_E, 0,
21598c2ecf20Sopenharmony_ci	 "Digi International DataFire Micro V (Europe)"},
21608c2ecf20Sopenharmony_ci	{HFC_DIGI_DF_M_IOM2_A, 0,
21618c2ecf20Sopenharmony_ci	 "Digi International DataFire Micro V IOM2 (North America)"},
21628c2ecf20Sopenharmony_ci	{HFC_DIGI_DF_M_A, 0,
21638c2ecf20Sopenharmony_ci	 "Digi International DataFire Micro V (North America)"},
21648c2ecf20Sopenharmony_ci	{HFC_SITECOM_DC105V2, 0, "Sitecom Connectivity DC-105 ISDN TA"},
21658c2ecf20Sopenharmony_ci	{},
21668c2ecf20Sopenharmony_ci};
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_cistatic const struct pci_device_id hfc_ids[] =
21698c2ecf20Sopenharmony_ci{
21708c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0),
21718c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[0] },
21728c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000),
21738c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[1] },
21748c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006),
21758c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[2] },
21768c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007),
21778c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[3] },
21788c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008),
21798c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[4] },
21808c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009),
21818c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[5] },
21828c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A),
21838c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[6] },
21848c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B),
21858c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[7] },
21868c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C),
21878c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[8] },
21888c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100),
21898c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[9] },
21908c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700),
21918c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[10] },
21928c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701),
21938c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[11] },
21948c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1),
21958c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[12] },
21968c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675),
21978c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[13] },
21988c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT),
21998c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[14] },
22008c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T),
22018c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[15] },
22028c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575),
22038c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[16] },
22048c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0),
22058c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[17] },
22068c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E),
22078c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[18] },
22088c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E),
22098c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[19] },
22108c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A),
22118c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[20] },
22128c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A),
22138c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[21] },
22148c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2),
22158c2ecf20Sopenharmony_ci	  (unsigned long) &hfc_map[22] },
22168c2ecf20Sopenharmony_ci	{},
22178c2ecf20Sopenharmony_ci};
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_cistatic int
22208c2ecf20Sopenharmony_cihfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
22218c2ecf20Sopenharmony_ci{
22228c2ecf20Sopenharmony_ci	int		err = -ENOMEM;
22238c2ecf20Sopenharmony_ci	struct hfc_pci	*card;
22248c2ecf20Sopenharmony_ci	struct _hfc_map	*m = (struct _hfc_map *)ent->driver_data;
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	card = kzalloc(sizeof(struct hfc_pci), GFP_KERNEL);
22278c2ecf20Sopenharmony_ci	if (!card) {
22288c2ecf20Sopenharmony_ci		printk(KERN_ERR "No kmem for HFC card\n");
22298c2ecf20Sopenharmony_ci		return err;
22308c2ecf20Sopenharmony_ci	}
22318c2ecf20Sopenharmony_ci	card->pdev = pdev;
22328c2ecf20Sopenharmony_ci	card->subtype = m->subtype;
22338c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
22348c2ecf20Sopenharmony_ci	if (err) {
22358c2ecf20Sopenharmony_ci		kfree(card);
22368c2ecf20Sopenharmony_ci		return err;
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	printk(KERN_INFO "mISDN_hfcpci: found adapter %s at %s\n",
22408c2ecf20Sopenharmony_ci	       m->name, pci_name(pdev));
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	card->irq = pdev->irq;
22438c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, card);
22448c2ecf20Sopenharmony_ci	err = setup_card(card);
22458c2ecf20Sopenharmony_ci	if (err)
22468c2ecf20Sopenharmony_ci		pci_set_drvdata(pdev, NULL);
22478c2ecf20Sopenharmony_ci	return err;
22488c2ecf20Sopenharmony_ci}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_cistatic void
22518c2ecf20Sopenharmony_cihfc_remove_pci(struct pci_dev *pdev)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	struct hfc_pci	*card = pci_get_drvdata(pdev);
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	if (card)
22568c2ecf20Sopenharmony_ci		release_card(card);
22578c2ecf20Sopenharmony_ci	else
22588c2ecf20Sopenharmony_ci		if (debug)
22598c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s: drvdata already removed\n",
22608c2ecf20Sopenharmony_ci			       __func__);
22618c2ecf20Sopenharmony_ci}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_cistatic struct pci_driver hfc_driver = {
22658c2ecf20Sopenharmony_ci	.name = "hfcpci",
22668c2ecf20Sopenharmony_ci	.probe = hfc_probe,
22678c2ecf20Sopenharmony_ci	.remove = hfc_remove_pci,
22688c2ecf20Sopenharmony_ci	.id_table = hfc_ids,
22698c2ecf20Sopenharmony_ci};
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_cistatic int
22728c2ecf20Sopenharmony_ci_hfcpci_softirq(struct device *dev, void *unused)
22738c2ecf20Sopenharmony_ci{
22748c2ecf20Sopenharmony_ci	struct hfc_pci  *hc = dev_get_drvdata(dev);
22758c2ecf20Sopenharmony_ci	struct bchannel *bch;
22768c2ecf20Sopenharmony_ci	if (hc == NULL)
22778c2ecf20Sopenharmony_ci		return 0;
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
22808c2ecf20Sopenharmony_ci		spin_lock_irq(&hc->lock);
22818c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
22828c2ecf20Sopenharmony_ci		if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
22838c2ecf20Sopenharmony_ci			main_rec_hfcpci(bch);
22848c2ecf20Sopenharmony_ci			tx_birq(bch);
22858c2ecf20Sopenharmony_ci		}
22868c2ecf20Sopenharmony_ci		bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2);
22878c2ecf20Sopenharmony_ci		if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */
22888c2ecf20Sopenharmony_ci			main_rec_hfcpci(bch);
22898c2ecf20Sopenharmony_ci			tx_birq(bch);
22908c2ecf20Sopenharmony_ci		}
22918c2ecf20Sopenharmony_ci		spin_unlock_irq(&hc->lock);
22928c2ecf20Sopenharmony_ci	}
22938c2ecf20Sopenharmony_ci	return 0;
22948c2ecf20Sopenharmony_ci}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_cistatic void
22978c2ecf20Sopenharmony_cihfcpci_softirq(struct timer_list *unused)
22988c2ecf20Sopenharmony_ci{
22998c2ecf20Sopenharmony_ci	WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, NULL,
23008c2ecf20Sopenharmony_ci				      _hfcpci_softirq) != 0);
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	/* if next event would be in the past ... */
23038c2ecf20Sopenharmony_ci	if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
23048c2ecf20Sopenharmony_ci		hfc_jiffies = jiffies + 1;
23058c2ecf20Sopenharmony_ci	else
23068c2ecf20Sopenharmony_ci		hfc_jiffies += tics;
23078c2ecf20Sopenharmony_ci	hfc_tl.expires = hfc_jiffies;
23088c2ecf20Sopenharmony_ci	add_timer(&hfc_tl);
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_cistatic int __init
23128c2ecf20Sopenharmony_ciHFC_init(void)
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	int		err;
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	if (!poll)
23178c2ecf20Sopenharmony_ci		poll = HFCPCI_BTRANS_THRESHOLD;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	if (poll != HFCPCI_BTRANS_THRESHOLD) {
23208c2ecf20Sopenharmony_ci		tics = (poll * HZ) / 8000;
23218c2ecf20Sopenharmony_ci		if (tics < 1)
23228c2ecf20Sopenharmony_ci			tics = 1;
23238c2ecf20Sopenharmony_ci		poll = (tics * 8000) / HZ;
23248c2ecf20Sopenharmony_ci		if (poll > 256 || poll < 8) {
23258c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Wrong poll value %d not in range "
23268c2ecf20Sopenharmony_ci			       "of 8..256.\n", __func__, poll);
23278c2ecf20Sopenharmony_ci			err = -EINVAL;
23288c2ecf20Sopenharmony_ci			return err;
23298c2ecf20Sopenharmony_ci		}
23308c2ecf20Sopenharmony_ci	}
23318c2ecf20Sopenharmony_ci	if (poll != HFCPCI_BTRANS_THRESHOLD) {
23328c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Using alternative poll value of %d\n",
23338c2ecf20Sopenharmony_ci		       __func__, poll);
23348c2ecf20Sopenharmony_ci		timer_setup(&hfc_tl, hfcpci_softirq, 0);
23358c2ecf20Sopenharmony_ci		hfc_tl.expires = jiffies + tics;
23368c2ecf20Sopenharmony_ci		hfc_jiffies = hfc_tl.expires;
23378c2ecf20Sopenharmony_ci		add_timer(&hfc_tl);
23388c2ecf20Sopenharmony_ci	} else
23398c2ecf20Sopenharmony_ci		tics = 0; /* indicate the use of controller's timer */
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	err = pci_register_driver(&hfc_driver);
23428c2ecf20Sopenharmony_ci	if (err) {
23438c2ecf20Sopenharmony_ci		if (timer_pending(&hfc_tl))
23448c2ecf20Sopenharmony_ci			del_timer(&hfc_tl);
23458c2ecf20Sopenharmony_ci	}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	return err;
23488c2ecf20Sopenharmony_ci}
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_cistatic void __exit
23518c2ecf20Sopenharmony_ciHFC_cleanup(void)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	if (timer_pending(&hfc_tl))
23548c2ecf20Sopenharmony_ci		del_timer_sync(&hfc_tl);
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	pci_unregister_driver(&hfc_driver);
23578c2ecf20Sopenharmony_ci}
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_cimodule_init(HFC_init);
23608c2ecf20Sopenharmony_cimodule_exit(HFC_cleanup);
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfc_ids);
2363