162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * hfcmulti.c  low level driver for hfc-4s/hfc-8s/hfc-e1 based cards
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author	Andreas Eversberg (jolly@eversberg.eu)
662306a36Sopenharmony_ci * ported to mqueue mechanism:
762306a36Sopenharmony_ci *		Peter Sprenger (sprengermoving-bytes.de)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * inspired by existing hfc-pci driver:
1062306a36Sopenharmony_ci * Copyright 1999  by Werner Cornelius (werner@isdn-development.de)
1162306a36Sopenharmony_ci * Copyright 2008  by Karsten Keil (kkeil@suse.de)
1262306a36Sopenharmony_ci * Copyright 2008  by Andreas Eversberg (jolly@eversberg.eu)
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Thanks to Cologne Chip AG for this great controller!
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * module parameters:
1962306a36Sopenharmony_ci * type:
2062306a36Sopenharmony_ci *	By default (0), the card is automatically detected.
2162306a36Sopenharmony_ci *	Or use the following combinations:
2262306a36Sopenharmony_ci *	Bit 0-7   = 0x00001 = HFC-E1 (1 port)
2362306a36Sopenharmony_ci * or	Bit 0-7   = 0x00004 = HFC-4S (4 ports)
2462306a36Sopenharmony_ci * or	Bit 0-7   = 0x00008 = HFC-8S (8 ports)
2562306a36Sopenharmony_ci *	Bit 8     = 0x00100 = uLaw (instead of aLaw)
2662306a36Sopenharmony_ci *	Bit 9     = 0x00200 = Disable DTMF detect on all B-channels via hardware
2762306a36Sopenharmony_ci *	Bit 10    = spare
2862306a36Sopenharmony_ci *	Bit 11    = 0x00800 = Force PCM bus into slave mode. (otherwhise auto)
2962306a36Sopenharmony_ci * or   Bit 12    = 0x01000 = Force PCM bus into master mode. (otherwhise auto)
3062306a36Sopenharmony_ci *	Bit 13	  = spare
3162306a36Sopenharmony_ci *	Bit 14    = 0x04000 = Use external ram (128K)
3262306a36Sopenharmony_ci *	Bit 15    = 0x08000 = Use external ram (512K)
3362306a36Sopenharmony_ci *	Bit 16    = 0x10000 = Use 64 timeslots instead of 32
3462306a36Sopenharmony_ci * or	Bit 17    = 0x20000 = Use 128 timeslots instead of anything else
3562306a36Sopenharmony_ci *	Bit 18    = spare
3662306a36Sopenharmony_ci *	Bit 19    = 0x80000 = Send the Watchdog a Signal (Dual E1 with Watchdog)
3762306a36Sopenharmony_ci * (all other bits are reserved and shall be 0)
3862306a36Sopenharmony_ci *	example: 0x20204 one HFC-4S with dtmf detection and 128 timeslots on PCM
3962306a36Sopenharmony_ci *		 bus (PCM master)
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * port: (optional or required for all ports on all installed cards)
4262306a36Sopenharmony_ci *	HFC-4S/HFC-8S only bits:
4362306a36Sopenharmony_ci *	Bit 0	  = 0x001 = Use master clock for this S/T interface
4462306a36Sopenharmony_ci *			    (ony once per chip).
4562306a36Sopenharmony_ci *	Bit 1     = 0x002 = transmitter line setup (non capacitive mode)
4662306a36Sopenharmony_ci *			    Don't use this unless you know what you are doing!
4762306a36Sopenharmony_ci *	Bit 2     = 0x004 = Disable E-channel. (No E-channel processing)
4862306a36Sopenharmony_ci *	example: 0x0001,0x0000,0x0000,0x0000 one HFC-4S with master clock
4962306a36Sopenharmony_ci *		 received from port 1
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci *	HFC-E1 only bits:
5262306a36Sopenharmony_ci *	Bit 0     = 0x0001 = interface: 0=copper, 1=optical
5362306a36Sopenharmony_ci *	Bit 1     = 0x0002 = reserved (later for 32 B-channels transparent mode)
5462306a36Sopenharmony_ci *	Bit 2     = 0x0004 = Report LOS
5562306a36Sopenharmony_ci *	Bit 3     = 0x0008 = Report AIS
5662306a36Sopenharmony_ci *	Bit 4     = 0x0010 = Report SLIP
5762306a36Sopenharmony_ci *	Bit 5     = 0x0020 = Report RDI
5862306a36Sopenharmony_ci *	Bit 8     = 0x0100 = Turn off CRC-4 Multiframe Mode, use double frame
5962306a36Sopenharmony_ci *			     mode instead.
6062306a36Sopenharmony_ci *	Bit 9	  = 0x0200 = Force get clock from interface, even in NT mode.
6162306a36Sopenharmony_ci * or	Bit 10	  = 0x0400 = Force put clock to interface, even in TE mode.
6262306a36Sopenharmony_ci *	Bit 11    = 0x0800 = Use direct RX clock for PCM sync rather than PLL.
6362306a36Sopenharmony_ci *			     (E1 only)
6462306a36Sopenharmony_ci *	Bit 12-13 = 0xX000 = elastic jitter buffer (1-3), Set both bits to 0
6562306a36Sopenharmony_ci *			     for default.
6662306a36Sopenharmony_ci * (all other bits are reserved and shall be 0)
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * debug:
6962306a36Sopenharmony_ci *	NOTE: only one debug value must be given for all cards
7062306a36Sopenharmony_ci *	enable debugging (see hfc_multi.h for debug options)
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * poll:
7362306a36Sopenharmony_ci *	NOTE: only one poll value must be given for all cards
7462306a36Sopenharmony_ci *	Give the number of samples for each fifo process.
7562306a36Sopenharmony_ci *	By default 128 is used. Decrease to reduce delay, increase to
7662306a36Sopenharmony_ci *	reduce cpu load. If unsure, don't mess with it!
7762306a36Sopenharmony_ci *	Valid is 8, 16, 32, 64, 128, 256.
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * pcm:
8062306a36Sopenharmony_ci *	NOTE: only one pcm value must be given for every card.
8162306a36Sopenharmony_ci *	The PCM bus id tells the mISDNdsp module about the connected PCM bus.
8262306a36Sopenharmony_ci *	By default (0), the PCM bus id is 100 for the card that is PCM master.
8362306a36Sopenharmony_ci *	If multiple cards are PCM master (because they are not interconnected),
8462306a36Sopenharmony_ci *	each card with PCM master will have increasing PCM id.
8562306a36Sopenharmony_ci *	All PCM busses with the same ID are expected to be connected and have
8662306a36Sopenharmony_ci *	common time slots slots.
8762306a36Sopenharmony_ci *	Only one chip of the PCM bus must be master, the others slave.
8862306a36Sopenharmony_ci *	-1 means no support of PCM bus not even.
8962306a36Sopenharmony_ci *	Omit this value, if all cards are interconnected or none is connected.
9062306a36Sopenharmony_ci *	If unsure, don't give this parameter.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * dmask and bmask:
9362306a36Sopenharmony_ci *	NOTE: One dmask value must be given for every HFC-E1 card.
9462306a36Sopenharmony_ci *	If omitted, the E1 card has D-channel on time slot 16, which is default.
9562306a36Sopenharmony_ci *	dmask is a 32 bit mask. The bit must be set for an alternate time slot.
9662306a36Sopenharmony_ci *	If multiple bits are set, multiple virtual card fragments are created.
9762306a36Sopenharmony_ci *	For each bit set, a bmask value must be given. Each bit on the bmask
9862306a36Sopenharmony_ci *	value stands for a B-channel. The bmask may not overlap with dmask or
9962306a36Sopenharmony_ci *	with other bmask values for that card.
10062306a36Sopenharmony_ci *	Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000
10162306a36Sopenharmony_ci *		This will create one fragment with D-channel on slot 1 with
10262306a36Sopenharmony_ci *		B-channels on slots 2..15, and a second fragment with D-channel
10362306a36Sopenharmony_ci *		on slot 17 with B-channels on slot 18..31. Slot 16 is unused.
10462306a36Sopenharmony_ci *	If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will
10562306a36Sopenharmony_ci *	not function.
10662306a36Sopenharmony_ci *	Example: dmask=0x00000001 bmask=0xfffffffe
10762306a36Sopenharmony_ci *		This will create a port with all 31 usable timeslots as
10862306a36Sopenharmony_ci *		B-channels.
10962306a36Sopenharmony_ci *	If no bits are set on bmask, no B-channel is created for that fragment.
11062306a36Sopenharmony_ci *	Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask)
11162306a36Sopenharmony_ci *		This will create 31 ports with one D-channel only.
11262306a36Sopenharmony_ci *	If you don't know how to use it, you don't need it!
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * iomode:
11562306a36Sopenharmony_ci *	NOTE: only one mode value must be given for every card.
11662306a36Sopenharmony_ci *	-> See hfc_multi.h for HFC_IO_MODE_* values
11762306a36Sopenharmony_ci *	By default, the IO mode is pci memory IO (MEMIO).
11862306a36Sopenharmony_ci *	Some cards require specific IO mode, so it cannot be changed.
11962306a36Sopenharmony_ci *	It may be useful to set IO mode to register io (REGIO) to solve
12062306a36Sopenharmony_ci *	PCI bridge problems.
12162306a36Sopenharmony_ci *	If unsure, don't give this parameter.
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * clockdelay_nt:
12462306a36Sopenharmony_ci *	NOTE: only one clockdelay_nt value must be given once for all cards.
12562306a36Sopenharmony_ci *	Give the value of the clock control register (A_ST_CLK_DLY)
12662306a36Sopenharmony_ci *	of the S/T interfaces in NT mode.
12762306a36Sopenharmony_ci *	This register is needed for the TBR3 certification, so don't change it.
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci * clockdelay_te:
13062306a36Sopenharmony_ci *	NOTE: only one clockdelay_te value must be given once
13162306a36Sopenharmony_ci *	Give the value of the clock control register (A_ST_CLK_DLY)
13262306a36Sopenharmony_ci *	of the S/T interfaces in TE mode.
13362306a36Sopenharmony_ci *	This register is needed for the TBR3 certification, so don't change it.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * clock:
13662306a36Sopenharmony_ci *	NOTE: only one clock value must be given once
13762306a36Sopenharmony_ci *	Selects interface with clock source for mISDN and applications.
13862306a36Sopenharmony_ci *	Set to card number starting with 1. Set to -1 to disable.
13962306a36Sopenharmony_ci *	By default, the first card is used as clock source.
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * hwid:
14262306a36Sopenharmony_ci *	NOTE: only one hwid value must be given once
14362306a36Sopenharmony_ci *	Enable special embedded devices with XHFC controllers.
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/*
14762306a36Sopenharmony_ci * debug register access (never use this, it will flood your system log)
14862306a36Sopenharmony_ci * #define HFC_REGISTER_DEBUG
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define HFC_MULTI_VERSION	"2.03"
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#include <linux/interrupt.h>
15462306a36Sopenharmony_ci#include <linux/module.h>
15562306a36Sopenharmony_ci#include <linux/slab.h>
15662306a36Sopenharmony_ci#include <linux/pci.h>
15762306a36Sopenharmony_ci#include <linux/delay.h>
15862306a36Sopenharmony_ci#include <linux/mISDNhw.h>
15962306a36Sopenharmony_ci#include <linux/mISDNdsp.h>
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/*
16262306a36Sopenharmony_ci  #define IRQCOUNT_DEBUG
16362306a36Sopenharmony_ci  #define IRQ_DEBUG
16462306a36Sopenharmony_ci*/
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#include "hfc_multi.h"
16762306a36Sopenharmony_ci#ifdef ECHOPREP
16862306a36Sopenharmony_ci#include "gaintab.h"
16962306a36Sopenharmony_ci#endif
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#define	MAX_CARDS	8
17262306a36Sopenharmony_ci#define	MAX_PORTS	(8 * MAX_CARDS)
17362306a36Sopenharmony_ci#define	MAX_FRAGS	(32 * MAX_CARDS)
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic LIST_HEAD(HFClist);
17662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(HFClock); /* global hfc list lock */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void ph_state_change(struct dchannel *);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic struct hfc_multi *syncmaster;
18162306a36Sopenharmony_cistatic int plxsd_master; /* if we have a master card (yet) */
18262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#define	TYP_E1		1
18562306a36Sopenharmony_ci#define	TYP_4S		4
18662306a36Sopenharmony_ci#define TYP_8S		8
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int poll_timer = 6;	/* default = 128 samples = 16ms */
18962306a36Sopenharmony_ci/* number of POLL_TIMER interrupts for G2 timeout (ca 1s) */
19062306a36Sopenharmony_cistatic int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30  };
19162306a36Sopenharmony_ci#define	CLKDEL_TE	0x0f	/* CLKDEL in TE mode */
19262306a36Sopenharmony_ci#define	CLKDEL_NT	0x6c	/* CLKDEL in NT mode
19362306a36Sopenharmony_ci				   (0x60 MUST be included!) */
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define	DIP_4S	0x1		/* DIP Switches for Beronet 1S/2S/4S cards */
19662306a36Sopenharmony_ci#define	DIP_8S	0x2		/* DIP Switches for Beronet 8S+ cards */
19762306a36Sopenharmony_ci#define	DIP_E1	0x3		/* DIP Switches for Beronet E1 cards */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/*
20062306a36Sopenharmony_ci * module stuff
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic uint	type[MAX_CARDS];
20462306a36Sopenharmony_cistatic int	pcm[MAX_CARDS];
20562306a36Sopenharmony_cistatic uint	dmask[MAX_CARDS];
20662306a36Sopenharmony_cistatic uint	bmask[MAX_FRAGS];
20762306a36Sopenharmony_cistatic uint	iomode[MAX_CARDS];
20862306a36Sopenharmony_cistatic uint	port[MAX_PORTS];
20962306a36Sopenharmony_cistatic uint	debug;
21062306a36Sopenharmony_cistatic uint	poll;
21162306a36Sopenharmony_cistatic int	clock;
21262306a36Sopenharmony_cistatic uint	timer;
21362306a36Sopenharmony_cistatic uint	clockdelay_te = CLKDEL_TE;
21462306a36Sopenharmony_cistatic uint	clockdelay_nt = CLKDEL_NT;
21562306a36Sopenharmony_ci#define HWID_NONE	0
21662306a36Sopenharmony_ci#define HWID_MINIP4	1
21762306a36Sopenharmony_ci#define HWID_MINIP8	2
21862306a36Sopenharmony_ci#define HWID_MINIP16	3
21962306a36Sopenharmony_cistatic uint	hwid = HWID_NONE;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int	HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Eversberg");
22462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
22562306a36Sopenharmony_ciMODULE_VERSION(HFC_MULTI_VERSION);
22662306a36Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR);
22762306a36Sopenharmony_cimodule_param(poll, uint, S_IRUGO | S_IWUSR);
22862306a36Sopenharmony_cimodule_param(clock, int, S_IRUGO | S_IWUSR);
22962306a36Sopenharmony_cimodule_param(timer, uint, S_IRUGO | S_IWUSR);
23062306a36Sopenharmony_cimodule_param(clockdelay_te, uint, S_IRUGO | S_IWUSR);
23162306a36Sopenharmony_cimodule_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR);
23262306a36Sopenharmony_cimodule_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
23362306a36Sopenharmony_cimodule_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR);
23462306a36Sopenharmony_cimodule_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR);
23562306a36Sopenharmony_cimodule_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR);
23662306a36Sopenharmony_cimodule_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR);
23762306a36Sopenharmony_cimodule_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
23862306a36Sopenharmony_cimodule_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
24162306a36Sopenharmony_ci#define HFC_outb(hc, reg, val)					\
24262306a36Sopenharmony_ci	(hc->HFC_outb(hc, reg, val, __func__, __LINE__))
24362306a36Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val)					\
24462306a36Sopenharmony_ci	(hc->HFC_outb_nodebug(hc, reg, val, __func__, __LINE__))
24562306a36Sopenharmony_ci#define HFC_inb(hc, reg)				\
24662306a36Sopenharmony_ci	(hc->HFC_inb(hc, reg, __func__, __LINE__))
24762306a36Sopenharmony_ci#define HFC_inb_nodebug(hc, reg)				\
24862306a36Sopenharmony_ci	(hc->HFC_inb_nodebug(hc, reg, __func__, __LINE__))
24962306a36Sopenharmony_ci#define HFC_inw(hc, reg)				\
25062306a36Sopenharmony_ci	(hc->HFC_inw(hc, reg, __func__, __LINE__))
25162306a36Sopenharmony_ci#define HFC_inw_nodebug(hc, reg)				\
25262306a36Sopenharmony_ci	(hc->HFC_inw_nodebug(hc, reg, __func__, __LINE__))
25362306a36Sopenharmony_ci#define HFC_wait(hc)				\
25462306a36Sopenharmony_ci	(hc->HFC_wait(hc, __func__, __LINE__))
25562306a36Sopenharmony_ci#define HFC_wait_nodebug(hc)				\
25662306a36Sopenharmony_ci	(hc->HFC_wait_nodebug(hc, __func__, __LINE__))
25762306a36Sopenharmony_ci#else
25862306a36Sopenharmony_ci#define HFC_outb(hc, reg, val)		(hc->HFC_outb(hc, reg, val))
25962306a36Sopenharmony_ci#define HFC_outb_nodebug(hc, reg, val)	(hc->HFC_outb_nodebug(hc, reg, val))
26062306a36Sopenharmony_ci#define HFC_inb(hc, reg)		(hc->HFC_inb(hc, reg))
26162306a36Sopenharmony_ci#define HFC_inb_nodebug(hc, reg)	(hc->HFC_inb_nodebug(hc, reg))
26262306a36Sopenharmony_ci#define HFC_inw(hc, reg)		(hc->HFC_inw(hc, reg))
26362306a36Sopenharmony_ci#define HFC_inw_nodebug(hc, reg)	(hc->HFC_inw_nodebug(hc, reg))
26462306a36Sopenharmony_ci#define HFC_wait(hc)			(hc->HFC_wait(hc))
26562306a36Sopenharmony_ci#define HFC_wait_nodebug(hc)		(hc->HFC_wait_nodebug(hc))
26662306a36Sopenharmony_ci#endif
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx
26962306a36Sopenharmony_ci#include "hfc_multi_8xx.h"
27062306a36Sopenharmony_ci#endif
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/* HFC_IO_MODE_PCIMEM */
27362306a36Sopenharmony_cistatic void
27462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
27562306a36Sopenharmony_ciHFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val,
27662306a36Sopenharmony_ci		const char *function, int line)
27762306a36Sopenharmony_ci#else
27862306a36Sopenharmony_ci	HFC_outb_pcimem(struct hfc_multi *hc, u_char reg, u_char val)
27962306a36Sopenharmony_ci#endif
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	writeb(val, hc->pci_membase + reg);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_cistatic u_char
28462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
28562306a36Sopenharmony_ciHFC_inb_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line)
28662306a36Sopenharmony_ci#else
28762306a36Sopenharmony_ci	HFC_inb_pcimem(struct hfc_multi *hc, u_char reg)
28862306a36Sopenharmony_ci#endif
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	return readb(hc->pci_membase + reg);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_cistatic u_short
29362306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
29462306a36Sopenharmony_ciHFC_inw_pcimem(struct hfc_multi *hc, u_char reg, const char *function, int line)
29562306a36Sopenharmony_ci#else
29662306a36Sopenharmony_ci	HFC_inw_pcimem(struct hfc_multi *hc, u_char reg)
29762306a36Sopenharmony_ci#endif
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	return readw(hc->pci_membase + reg);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_cistatic void
30262306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
30362306a36Sopenharmony_ciHFC_wait_pcimem(struct hfc_multi *hc, const char *function, int line)
30462306a36Sopenharmony_ci#else
30562306a36Sopenharmony_ci	HFC_wait_pcimem(struct hfc_multi *hc)
30662306a36Sopenharmony_ci#endif
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	while (readb(hc->pci_membase + R_STATUS) & V_BUSY)
30962306a36Sopenharmony_ci		cpu_relax();
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/* HFC_IO_MODE_REGIO */
31362306a36Sopenharmony_cistatic void
31462306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
31562306a36Sopenharmony_ciHFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val,
31662306a36Sopenharmony_ci	       const char *function, int line)
31762306a36Sopenharmony_ci#else
31862306a36Sopenharmony_ci	HFC_outb_regio(struct hfc_multi *hc, u_char reg, u_char val)
31962306a36Sopenharmony_ci#endif
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	outb(reg, hc->pci_iobase + 4);
32262306a36Sopenharmony_ci	outb(val, hc->pci_iobase);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_cistatic u_char
32562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
32662306a36Sopenharmony_ciHFC_inb_regio(struct hfc_multi *hc, u_char reg, const char *function, int line)
32762306a36Sopenharmony_ci#else
32862306a36Sopenharmony_ci	HFC_inb_regio(struct hfc_multi *hc, u_char reg)
32962306a36Sopenharmony_ci#endif
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	outb(reg, hc->pci_iobase + 4);
33262306a36Sopenharmony_ci	return inb(hc->pci_iobase);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_cistatic u_short
33562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
33662306a36Sopenharmony_ciHFC_inw_regio(struct hfc_multi *hc, u_char reg, const char *function, int line)
33762306a36Sopenharmony_ci#else
33862306a36Sopenharmony_ci	HFC_inw_regio(struct hfc_multi *hc, u_char reg)
33962306a36Sopenharmony_ci#endif
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	outb(reg, hc->pci_iobase + 4);
34262306a36Sopenharmony_ci	return inw(hc->pci_iobase);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_cistatic void
34562306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
34662306a36Sopenharmony_ciHFC_wait_regio(struct hfc_multi *hc, const char *function, int line)
34762306a36Sopenharmony_ci#else
34862306a36Sopenharmony_ci	HFC_wait_regio(struct hfc_multi *hc)
34962306a36Sopenharmony_ci#endif
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	outb(R_STATUS, hc->pci_iobase + 4);
35262306a36Sopenharmony_ci	while (inb(hc->pci_iobase) & V_BUSY)
35362306a36Sopenharmony_ci		cpu_relax();
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
35762306a36Sopenharmony_cistatic void
35862306a36Sopenharmony_ciHFC_outb_debug(struct hfc_multi *hc, u_char reg, u_char val,
35962306a36Sopenharmony_ci	       const char *function, int line)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	char regname[256] = "", bits[9] = "xxxxxxxx";
36262306a36Sopenharmony_ci	int i;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	i = -1;
36562306a36Sopenharmony_ci	while (hfc_register_names[++i].name) {
36662306a36Sopenharmony_ci		if (hfc_register_names[i].reg == reg)
36762306a36Sopenharmony_ci			strcat(regname, hfc_register_names[i].name);
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci	if (regname[0] == '\0')
37062306a36Sopenharmony_ci		strcpy(regname, "register");
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	bits[7] = '0' + (!!(val & 1));
37362306a36Sopenharmony_ci	bits[6] = '0' + (!!(val & 2));
37462306a36Sopenharmony_ci	bits[5] = '0' + (!!(val & 4));
37562306a36Sopenharmony_ci	bits[4] = '0' + (!!(val & 8));
37662306a36Sopenharmony_ci	bits[3] = '0' + (!!(val & 16));
37762306a36Sopenharmony_ci	bits[2] = '0' + (!!(val & 32));
37862306a36Sopenharmony_ci	bits[1] = '0' + (!!(val & 64));
37962306a36Sopenharmony_ci	bits[0] = '0' + (!!(val & 128));
38062306a36Sopenharmony_ci	printk(KERN_DEBUG
38162306a36Sopenharmony_ci	       "HFC_outb(chip %d, %02x=%s, 0x%02x=%s); in %s() line %d\n",
38262306a36Sopenharmony_ci	       hc->id, reg, regname, val, bits, function, line);
38362306a36Sopenharmony_ci	HFC_outb_nodebug(hc, reg, val);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_cistatic u_char
38662306a36Sopenharmony_ciHFC_inb_debug(struct hfc_multi *hc, u_char reg, const char *function, int line)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	char regname[256] = "", bits[9] = "xxxxxxxx";
38962306a36Sopenharmony_ci	u_char val = HFC_inb_nodebug(hc, reg);
39062306a36Sopenharmony_ci	int i;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	i = 0;
39362306a36Sopenharmony_ci	while (hfc_register_names[i++].name)
39462306a36Sopenharmony_ci		;
39562306a36Sopenharmony_ci	while (hfc_register_names[++i].name) {
39662306a36Sopenharmony_ci		if (hfc_register_names[i].reg == reg)
39762306a36Sopenharmony_ci			strcat(regname, hfc_register_names[i].name);
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci	if (regname[0] == '\0')
40062306a36Sopenharmony_ci		strcpy(regname, "register");
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	bits[7] = '0' + (!!(val & 1));
40362306a36Sopenharmony_ci	bits[6] = '0' + (!!(val & 2));
40462306a36Sopenharmony_ci	bits[5] = '0' + (!!(val & 4));
40562306a36Sopenharmony_ci	bits[4] = '0' + (!!(val & 8));
40662306a36Sopenharmony_ci	bits[3] = '0' + (!!(val & 16));
40762306a36Sopenharmony_ci	bits[2] = '0' + (!!(val & 32));
40862306a36Sopenharmony_ci	bits[1] = '0' + (!!(val & 64));
40962306a36Sopenharmony_ci	bits[0] = '0' + (!!(val & 128));
41062306a36Sopenharmony_ci	printk(KERN_DEBUG
41162306a36Sopenharmony_ci	       "HFC_inb(chip %d, %02x=%s) = 0x%02x=%s; in %s() line %d\n",
41262306a36Sopenharmony_ci	       hc->id, reg, regname, val, bits, function, line);
41362306a36Sopenharmony_ci	return val;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_cistatic u_short
41662306a36Sopenharmony_ciHFC_inw_debug(struct hfc_multi *hc, u_char reg, const char *function, int line)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	char regname[256] = "";
41962306a36Sopenharmony_ci	u_short val = HFC_inw_nodebug(hc, reg);
42062306a36Sopenharmony_ci	int i;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	i = 0;
42362306a36Sopenharmony_ci	while (hfc_register_names[i++].name)
42462306a36Sopenharmony_ci		;
42562306a36Sopenharmony_ci	while (hfc_register_names[++i].name) {
42662306a36Sopenharmony_ci		if (hfc_register_names[i].reg == reg)
42762306a36Sopenharmony_ci			strcat(regname, hfc_register_names[i].name);
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	if (regname[0] == '\0')
43062306a36Sopenharmony_ci		strcpy(regname, "register");
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	printk(KERN_DEBUG
43362306a36Sopenharmony_ci	       "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n",
43462306a36Sopenharmony_ci	       hc->id, reg, regname, val, function, line);
43562306a36Sopenharmony_ci	return val;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_cistatic void
43862306a36Sopenharmony_ciHFC_wait_debug(struct hfc_multi *hc, const char *function, int line)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n",
44162306a36Sopenharmony_ci	       hc->id, function, line);
44262306a36Sopenharmony_ci	HFC_wait_nodebug(hc);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci#endif
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/* write fifo data (REGIO) */
44762306a36Sopenharmony_cistatic void
44862306a36Sopenharmony_ciwrite_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	outb(A_FIFO_DATA0, (hc->pci_iobase) + 4);
45162306a36Sopenharmony_ci	while (len >> 2) {
45262306a36Sopenharmony_ci		outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase);
45362306a36Sopenharmony_ci		data += 4;
45462306a36Sopenharmony_ci		len -= 4;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci	while (len >> 1) {
45762306a36Sopenharmony_ci		outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase);
45862306a36Sopenharmony_ci		data += 2;
45962306a36Sopenharmony_ci		len -= 2;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	while (len) {
46262306a36Sopenharmony_ci		outb(*data, hc->pci_iobase);
46362306a36Sopenharmony_ci		data++;
46462306a36Sopenharmony_ci		len--;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci/* write fifo data (PCIMEM) */
46862306a36Sopenharmony_cistatic void
46962306a36Sopenharmony_ciwrite_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	while (len >> 2) {
47262306a36Sopenharmony_ci		writel(cpu_to_le32(*(u32 *)data),
47362306a36Sopenharmony_ci		       hc->pci_membase + A_FIFO_DATA0);
47462306a36Sopenharmony_ci		data += 4;
47562306a36Sopenharmony_ci		len -= 4;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	while (len >> 1) {
47862306a36Sopenharmony_ci		writew(cpu_to_le16(*(u16 *)data),
47962306a36Sopenharmony_ci		       hc->pci_membase + A_FIFO_DATA0);
48062306a36Sopenharmony_ci		data += 2;
48162306a36Sopenharmony_ci		len -= 2;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	while (len) {
48462306a36Sopenharmony_ci		writeb(*data, hc->pci_membase + A_FIFO_DATA0);
48562306a36Sopenharmony_ci		data++;
48662306a36Sopenharmony_ci		len--;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/* read fifo data (REGIO) */
49162306a36Sopenharmony_cistatic void
49262306a36Sopenharmony_ciread_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	outb(A_FIFO_DATA0, (hc->pci_iobase) + 4);
49562306a36Sopenharmony_ci	while (len >> 2) {
49662306a36Sopenharmony_ci		*(u32 *)data = le32_to_cpu(inl(hc->pci_iobase));
49762306a36Sopenharmony_ci		data += 4;
49862306a36Sopenharmony_ci		len -= 4;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	while (len >> 1) {
50162306a36Sopenharmony_ci		*(u16 *)data = le16_to_cpu(inw(hc->pci_iobase));
50262306a36Sopenharmony_ci		data += 2;
50362306a36Sopenharmony_ci		len -= 2;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci	while (len) {
50662306a36Sopenharmony_ci		*data = inb(hc->pci_iobase);
50762306a36Sopenharmony_ci		data++;
50862306a36Sopenharmony_ci		len--;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/* read fifo data (PCIMEM) */
51362306a36Sopenharmony_cistatic void
51462306a36Sopenharmony_ciread_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	while (len >> 2) {
51762306a36Sopenharmony_ci		*(u32 *)data =
51862306a36Sopenharmony_ci			le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0));
51962306a36Sopenharmony_ci		data += 4;
52062306a36Sopenharmony_ci		len -= 4;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci	while (len >> 1) {
52362306a36Sopenharmony_ci		*(u16 *)data =
52462306a36Sopenharmony_ci			le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0));
52562306a36Sopenharmony_ci		data += 2;
52662306a36Sopenharmony_ci		len -= 2;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci	while (len) {
52962306a36Sopenharmony_ci		*data = readb(hc->pci_membase + A_FIFO_DATA0);
53062306a36Sopenharmony_ci		data++;
53162306a36Sopenharmony_ci		len--;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic void
53662306a36Sopenharmony_cienable_hwirq(struct hfc_multi *hc)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN;
53962306a36Sopenharmony_ci	HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void
54362306a36Sopenharmony_cidisable_hwirq(struct hfc_multi *hc)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN);
54662306a36Sopenharmony_ci	HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl);
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci#define	NUM_EC 2
55062306a36Sopenharmony_ci#define	MAX_TDM_CHAN 32
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic inline void
55462306a36Sopenharmony_cienablepcibridge(struct hfc_multi *c)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); /* was _io before */
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic inline void
56062306a36Sopenharmony_cidisablepcibridge(struct hfc_multi *c)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x2); /* was _io before */
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic inline unsigned char
56662306a36Sopenharmony_cireadpcibridge(struct hfc_multi *hc, unsigned char address)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	unsigned short cipv;
56962306a36Sopenharmony_ci	unsigned char data;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (!hc->pci_iobase)
57262306a36Sopenharmony_ci		return 0;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* slow down a PCI read access by 1 PCI clock cycle */
57562306a36Sopenharmony_ci	HFC_outb(hc, R_CTRL, 0x4); /*was _io before*/
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (address == 0)
57862306a36Sopenharmony_ci		cipv = 0x4000;
57962306a36Sopenharmony_ci	else
58062306a36Sopenharmony_ci		cipv = 0x5800;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* select local bridge port address by writing to CIP port */
58362306a36Sopenharmony_ci	/* data = HFC_inb(c, cipv); * was _io before */
58462306a36Sopenharmony_ci	outw(cipv, hc->pci_iobase + 4);
58562306a36Sopenharmony_ci	data = inb(hc->pci_iobase);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* restore R_CTRL for normal PCI read cycle speed */
58862306a36Sopenharmony_ci	HFC_outb(hc, R_CTRL, 0x0); /* was _io before */
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return data;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic inline void
59462306a36Sopenharmony_ciwritepcibridge(struct hfc_multi *hc, unsigned char address, unsigned char data)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	unsigned short cipv;
59762306a36Sopenharmony_ci	unsigned int datav;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (!hc->pci_iobase)
60062306a36Sopenharmony_ci		return;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (address == 0)
60362306a36Sopenharmony_ci		cipv = 0x4000;
60462306a36Sopenharmony_ci	else
60562306a36Sopenharmony_ci		cipv = 0x5800;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	/* select local bridge port address by writing to CIP port */
60862306a36Sopenharmony_ci	outw(cipv, hc->pci_iobase + 4);
60962306a36Sopenharmony_ci	/* define a 32 bit dword with 4 identical bytes for write sequence */
61062306a36Sopenharmony_ci	datav = data | ((__u32) data << 8) | ((__u32) data << 16) |
61162306a36Sopenharmony_ci		((__u32) data << 24);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/*
61462306a36Sopenharmony_ci	 * write this 32 bit dword to the bridge data port
61562306a36Sopenharmony_ci	 * this will initiate a write sequence of up to 4 writes to the same
61662306a36Sopenharmony_ci	 * address on the local bus interface the number of write accesses
61762306a36Sopenharmony_ci	 * is undefined but >=1 and depends on the next PCI transaction
61862306a36Sopenharmony_ci	 * during write sequence on the local bus
61962306a36Sopenharmony_ci	 */
62062306a36Sopenharmony_ci	outl(datav, hc->pci_iobase);
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic inline void
62462306a36Sopenharmony_cicpld_set_reg(struct hfc_multi *hc, unsigned char reg)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	/* Do data pin read low byte */
62762306a36Sopenharmony_ci	HFC_outb(hc, R_GPIO_OUT1, reg);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic inline void
63162306a36Sopenharmony_cicpld_write_reg(struct hfc_multi *hc, unsigned char reg, unsigned char val)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	cpld_set_reg(hc, reg);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	enablepcibridge(hc);
63662306a36Sopenharmony_ci	writepcibridge(hc, 1, val);
63762306a36Sopenharmony_ci	disablepcibridge(hc);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic inline void
64362306a36Sopenharmony_civpm_write_address(struct hfc_multi *hc, unsigned short addr)
64462306a36Sopenharmony_ci{
64562306a36Sopenharmony_ci	cpld_write_reg(hc, 0, 0xff & addr);
64662306a36Sopenharmony_ci	cpld_write_reg(hc, 1, 0x01 & (addr >> 8));
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic inline unsigned char
65062306a36Sopenharmony_civpm_in(struct hfc_multi *c, int which, unsigned short addr)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	unsigned char res;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	vpm_write_address(c, addr);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (!which)
65762306a36Sopenharmony_ci		cpld_set_reg(c, 2);
65862306a36Sopenharmony_ci	else
65962306a36Sopenharmony_ci		cpld_set_reg(c, 3);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	enablepcibridge(c);
66262306a36Sopenharmony_ci	res = readpcibridge(c, 1);
66362306a36Sopenharmony_ci	disablepcibridge(c);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	cpld_set_reg(c, 0);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return res;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic inline void
67162306a36Sopenharmony_civpm_out(struct hfc_multi *c, int which, unsigned short addr,
67262306a36Sopenharmony_ci	unsigned char data)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	vpm_write_address(c, addr);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	enablepcibridge(c);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (!which)
67962306a36Sopenharmony_ci		cpld_set_reg(c, 2);
68062306a36Sopenharmony_ci	else
68162306a36Sopenharmony_ci		cpld_set_reg(c, 3);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	writepcibridge(c, 1, data);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	cpld_set_reg(c, 0);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	disablepcibridge(c);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	{
69062306a36Sopenharmony_ci		unsigned char regin;
69162306a36Sopenharmony_ci		regin = vpm_in(c, which, addr);
69262306a36Sopenharmony_ci		if (regin != data)
69362306a36Sopenharmony_ci			printk(KERN_DEBUG "Wrote 0x%x to register 0x%x but got back "
69462306a36Sopenharmony_ci			       "0x%x\n", data, addr, regin);
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic void
70162306a36Sopenharmony_civpm_init(struct hfc_multi *wc)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	unsigned char reg;
70462306a36Sopenharmony_ci	unsigned int mask;
70562306a36Sopenharmony_ci	unsigned int i, x, y;
70662306a36Sopenharmony_ci	unsigned int ver;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	for (x = 0; x < NUM_EC; x++) {
70962306a36Sopenharmony_ci		/* Setup GPIO's */
71062306a36Sopenharmony_ci		if (!x) {
71162306a36Sopenharmony_ci			ver = vpm_in(wc, x, 0x1a0);
71262306a36Sopenharmony_ci			printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver);
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		for (y = 0; y < 4; y++) {
71662306a36Sopenharmony_ci			vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
71762306a36Sopenharmony_ci			vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
71862306a36Sopenharmony_ci			vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		/* Setup TDM path - sets fsync and tdm_clk as inputs */
72262306a36Sopenharmony_ci		reg = vpm_in(wc, x, 0x1a3); /* misc_con */
72362306a36Sopenharmony_ci		vpm_out(wc, x, 0x1a3, reg & ~2);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		/* Setup Echo length (256 taps) */
72662306a36Sopenharmony_ci		vpm_out(wc, x, 0x022, 1);
72762306a36Sopenharmony_ci		vpm_out(wc, x, 0x023, 0xff);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		/* Setup timeslots */
73062306a36Sopenharmony_ci		vpm_out(wc, x, 0x02f, 0x00);
73162306a36Sopenharmony_ci		mask = 0x02020202 << (x * 4);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		/* Setup the tdm channel masks for all chips */
73462306a36Sopenharmony_ci		for (i = 0; i < 4; i++)
73562306a36Sopenharmony_ci			vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		/* Setup convergence rate */
73862306a36Sopenharmony_ci		printk(KERN_DEBUG "VPM: A-law mode\n");
73962306a36Sopenharmony_ci		reg = 0x00 | 0x10 | 0x01;
74062306a36Sopenharmony_ci		vpm_out(wc, x, 0x20, reg);
74162306a36Sopenharmony_ci		printk(KERN_DEBUG "VPM reg 0x20 is %x\n", reg);
74262306a36Sopenharmony_ci		/*vpm_out(wc, x, 0x20, (0x00 | 0x08 | 0x20 | 0x10)); */
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		vpm_out(wc, x, 0x24, 0x02);
74562306a36Sopenharmony_ci		reg = vpm_in(wc, x, 0x24);
74662306a36Sopenharmony_ci		printk(KERN_DEBUG "NLP Thresh is set to %d (0x%x)\n", reg, reg);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		/* Initialize echo cans */
74962306a36Sopenharmony_ci		for (i = 0; i < MAX_TDM_CHAN; i++) {
75062306a36Sopenharmony_ci			if (mask & (0x00000001 << i))
75162306a36Sopenharmony_ci				vpm_out(wc, x, i, 0x00);
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		/*
75562306a36Sopenharmony_ci		 * ARM arch at least disallows a udelay of
75662306a36Sopenharmony_ci		 * more than 2ms... it gives a fake "__bad_udelay"
75762306a36Sopenharmony_ci		 * reference at link-time.
75862306a36Sopenharmony_ci		 * long delays in kernel code are pretty sucky anyway
75962306a36Sopenharmony_ci		 * for now work around it using 5 x 2ms instead of 1 x 10ms
76062306a36Sopenharmony_ci		 */
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		udelay(2000);
76362306a36Sopenharmony_ci		udelay(2000);
76462306a36Sopenharmony_ci		udelay(2000);
76562306a36Sopenharmony_ci		udelay(2000);
76662306a36Sopenharmony_ci		udelay(2000);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		/* Put in bypass mode */
76962306a36Sopenharmony_ci		for (i = 0; i < MAX_TDM_CHAN; i++) {
77062306a36Sopenharmony_ci			if (mask & (0x00000001 << i))
77162306a36Sopenharmony_ci				vpm_out(wc, x, i, 0x01);
77262306a36Sopenharmony_ci		}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci		/* Enable bypass */
77562306a36Sopenharmony_ci		for (i = 0; i < MAX_TDM_CHAN; i++) {
77662306a36Sopenharmony_ci			if (mask & (0x00000001 << i))
77762306a36Sopenharmony_ci				vpm_out(wc, x, 0x78 + i, 0x01);
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci#ifdef UNUSED
78462306a36Sopenharmony_cistatic void
78562306a36Sopenharmony_civpm_check(struct hfc_multi *hctmp)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	unsigned char gpi2;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	gpi2 = HFC_inb(hctmp, R_GPI_IN2);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if ((gpi2 & 0x3) != 0x3)
79262306a36Sopenharmony_ci		printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2);
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci#endif /* UNUSED */
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/*
79862306a36Sopenharmony_ci * Interface to enable/disable the HW Echocan
79962306a36Sopenharmony_ci *
80062306a36Sopenharmony_ci * these functions are called within a spin_lock_irqsave on
80162306a36Sopenharmony_ci * the channel instance lock, so we are not disturbed by irqs
80262306a36Sopenharmony_ci *
80362306a36Sopenharmony_ci * we can later easily change the interface to make  other
80462306a36Sopenharmony_ci * things configurable, for now we configure the taps
80562306a36Sopenharmony_ci *
80662306a36Sopenharmony_ci */
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic void
80962306a36Sopenharmony_civpm_echocan_on(struct hfc_multi *hc, int ch, int taps)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	unsigned int timeslot;
81262306a36Sopenharmony_ci	unsigned int unit;
81362306a36Sopenharmony_ci	struct bchannel *bch = hc->chan[ch].bch;
81462306a36Sopenharmony_ci#ifdef TXADJ
81562306a36Sopenharmony_ci	int txadj = -4;
81662306a36Sopenharmony_ci	struct sk_buff *skb;
81762306a36Sopenharmony_ci#endif
81862306a36Sopenharmony_ci	if (hc->chan[ch].protocol != ISDN_P_B_RAW)
81962306a36Sopenharmony_ci		return;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (!bch)
82262306a36Sopenharmony_ci		return;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci#ifdef TXADJ
82562306a36Sopenharmony_ci	skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX,
82662306a36Sopenharmony_ci			       sizeof(int), &txadj, GFP_ATOMIC);
82762306a36Sopenharmony_ci	if (skb)
82862306a36Sopenharmony_ci		recv_Bchannel_skb(bch, skb);
82962306a36Sopenharmony_ci#endif
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1;
83262306a36Sopenharmony_ci	unit = ch % 4;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	printk(KERN_NOTICE "vpm_echocan_on called taps [%d] on timeslot %d\n",
83562306a36Sopenharmony_ci	       taps, timeslot);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	vpm_out(hc, unit, timeslot, 0x7e);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic void
84162306a36Sopenharmony_civpm_echocan_off(struct hfc_multi *hc, int ch)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	unsigned int timeslot;
84462306a36Sopenharmony_ci	unsigned int unit;
84562306a36Sopenharmony_ci	struct bchannel *bch = hc->chan[ch].bch;
84662306a36Sopenharmony_ci#ifdef TXADJ
84762306a36Sopenharmony_ci	int txadj = 0;
84862306a36Sopenharmony_ci	struct sk_buff *skb;
84962306a36Sopenharmony_ci#endif
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	if (hc->chan[ch].protocol != ISDN_P_B_RAW)
85262306a36Sopenharmony_ci		return;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (!bch)
85562306a36Sopenharmony_ci		return;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci#ifdef TXADJ
85862306a36Sopenharmony_ci	skb = _alloc_mISDN_skb(PH_CONTROL_IND, HFC_VOL_CHANGE_TX,
85962306a36Sopenharmony_ci			       sizeof(int), &txadj, GFP_ATOMIC);
86062306a36Sopenharmony_ci	if (skb)
86162306a36Sopenharmony_ci		recv_Bchannel_skb(bch, skb);
86262306a36Sopenharmony_ci#endif
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	timeslot = ((ch / 4) * 8) + ((ch % 4) * 4) + 1;
86562306a36Sopenharmony_ci	unit = ch % 4;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	printk(KERN_NOTICE "vpm_echocan_off called on timeslot %d\n",
86862306a36Sopenharmony_ci	       timeslot);
86962306a36Sopenharmony_ci	/* FILLME */
87062306a36Sopenharmony_ci	vpm_out(hc, unit, timeslot, 0x01);
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci/*
87562306a36Sopenharmony_ci * Speech Design resync feature
87662306a36Sopenharmony_ci * NOTE: This is called sometimes outside interrupt handler.
87762306a36Sopenharmony_ci * We must lock irqsave, so no other interrupt (other card) will occur!
87862306a36Sopenharmony_ci * Also multiple interrupts may nest, so must lock each access (lists, card)!
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistatic inline void
88162306a36Sopenharmony_cihfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	struct hfc_multi *hc, *next, *pcmmaster = NULL;
88462306a36Sopenharmony_ci	void __iomem *plx_acc_32;
88562306a36Sopenharmony_ci	u_int pv;
88662306a36Sopenharmony_ci	u_long flags;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	spin_lock_irqsave(&HFClock, flags);
88962306a36Sopenharmony_ci	spin_lock(&plx_lock); /* must be locked inside other locks */
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_PLXSD)
89262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: RESYNC(syncmaster=0x%p)\n",
89362306a36Sopenharmony_ci		       __func__, syncmaster);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* select new master */
89662306a36Sopenharmony_ci	if (newmaster) {
89762306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_PLXSD)
89862306a36Sopenharmony_ci			printk(KERN_DEBUG "using provided controller\n");
89962306a36Sopenharmony_ci	} else {
90062306a36Sopenharmony_ci		list_for_each_entry_safe(hc, next, &HFClist, list) {
90162306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
90262306a36Sopenharmony_ci				if (hc->syncronized) {
90362306a36Sopenharmony_ci					newmaster = hc;
90462306a36Sopenharmony_ci					break;
90562306a36Sopenharmony_ci				}
90662306a36Sopenharmony_ci			}
90762306a36Sopenharmony_ci		}
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* Disable sync of all cards */
91162306a36Sopenharmony_ci	list_for_each_entry_safe(hc, next, &HFClist, list) {
91262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
91362306a36Sopenharmony_ci			plx_acc_32 = hc->plx_membase + PLX_GPIOC;
91462306a36Sopenharmony_ci			pv = readl(plx_acc_32);
91562306a36Sopenharmony_ci			pv &= ~PLX_SYNC_O_EN;
91662306a36Sopenharmony_ci			writel(pv, plx_acc_32);
91762306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) {
91862306a36Sopenharmony_ci				pcmmaster = hc;
91962306a36Sopenharmony_ci				if (hc->ctype == HFC_TYPE_E1) {
92062306a36Sopenharmony_ci					if (debug & DEBUG_HFCMULTI_PLXSD)
92162306a36Sopenharmony_ci						printk(KERN_DEBUG
92262306a36Sopenharmony_ci						       "Schedule SYNC_I\n");
92362306a36Sopenharmony_ci					hc->e1_resync |= 1; /* get SYNC_I */
92462306a36Sopenharmony_ci				}
92562306a36Sopenharmony_ci			}
92662306a36Sopenharmony_ci		}
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (newmaster) {
93062306a36Sopenharmony_ci		hc = newmaster;
93162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_PLXSD)
93262306a36Sopenharmony_ci			printk(KERN_DEBUG "id=%d (0x%p) = syncronized with "
93362306a36Sopenharmony_ci			       "interface.\n", hc->id, hc);
93462306a36Sopenharmony_ci		/* Enable new sync master */
93562306a36Sopenharmony_ci		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
93662306a36Sopenharmony_ci		pv = readl(plx_acc_32);
93762306a36Sopenharmony_ci		pv |= PLX_SYNC_O_EN;
93862306a36Sopenharmony_ci		writel(pv, plx_acc_32);
93962306a36Sopenharmony_ci		/* switch to jatt PLL, if not disabled by RX_SYNC */
94062306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1
94162306a36Sopenharmony_ci		    && !test_bit(HFC_CHIP_RX_SYNC, &hc->chip)) {
94262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
94362306a36Sopenharmony_ci				printk(KERN_DEBUG "Schedule jatt PLL\n");
94462306a36Sopenharmony_ci			hc->e1_resync |= 2; /* switch to jatt */
94562306a36Sopenharmony_ci		}
94662306a36Sopenharmony_ci	} else {
94762306a36Sopenharmony_ci		if (pcmmaster) {
94862306a36Sopenharmony_ci			hc = pcmmaster;
94962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
95062306a36Sopenharmony_ci				printk(KERN_DEBUG
95162306a36Sopenharmony_ci				       "id=%d (0x%p) = PCM master syncronized "
95262306a36Sopenharmony_ci				       "with QUARTZ\n", hc->id, hc);
95362306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_E1) {
95462306a36Sopenharmony_ci				/* Use the crystal clock for the PCM
95562306a36Sopenharmony_ci				   master card */
95662306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_PLXSD)
95762306a36Sopenharmony_ci					printk(KERN_DEBUG
95862306a36Sopenharmony_ci					       "Schedule QUARTZ for HFC-E1\n");
95962306a36Sopenharmony_ci				hc->e1_resync |= 4; /* switch quartz */
96062306a36Sopenharmony_ci			} else {
96162306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_PLXSD)
96262306a36Sopenharmony_ci					printk(KERN_DEBUG
96362306a36Sopenharmony_ci					       "QUARTZ is automatically "
96462306a36Sopenharmony_ci					       "enabled by HFC-%dS\n", hc->ctype);
96562306a36Sopenharmony_ci			}
96662306a36Sopenharmony_ci			plx_acc_32 = hc->plx_membase + PLX_GPIOC;
96762306a36Sopenharmony_ci			pv = readl(plx_acc_32);
96862306a36Sopenharmony_ci			pv |= PLX_SYNC_O_EN;
96962306a36Sopenharmony_ci			writel(pv, plx_acc_32);
97062306a36Sopenharmony_ci		} else
97162306a36Sopenharmony_ci			if (!rm)
97262306a36Sopenharmony_ci				printk(KERN_ERR "%s no pcm master, this MUST "
97362306a36Sopenharmony_ci				       "not happen!\n", __func__);
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	syncmaster = newmaster;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	spin_unlock(&plx_lock);
97862306a36Sopenharmony_ci	spin_unlock_irqrestore(&HFClock, flags);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci/* This must be called AND hc must be locked irqsave!!! */
98262306a36Sopenharmony_cistatic inline void
98362306a36Sopenharmony_ciplxsd_checksync(struct hfc_multi *hc, int rm)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	if (hc->syncronized) {
98662306a36Sopenharmony_ci		if (syncmaster == NULL) {
98762306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
98862306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: GOT sync on card %d"
98962306a36Sopenharmony_ci				       " (id=%d)\n", __func__, hc->id + 1,
99062306a36Sopenharmony_ci				       hc->id);
99162306a36Sopenharmony_ci			hfcmulti_resync(hc, hc, rm);
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci	} else {
99462306a36Sopenharmony_ci		if (syncmaster == hc) {
99562306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
99662306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: LOST sync on card %d"
99762306a36Sopenharmony_ci				       " (id=%d)\n", __func__, hc->id + 1,
99862306a36Sopenharmony_ci				       hc->id);
99962306a36Sopenharmony_ci			hfcmulti_resync(hc, NULL, rm);
100062306a36Sopenharmony_ci		}
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci/*
100662306a36Sopenharmony_ci * free hardware resources used by driver
100762306a36Sopenharmony_ci */
100862306a36Sopenharmony_cistatic void
100962306a36Sopenharmony_cirelease_io_hfcmulti(struct hfc_multi *hc)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	void __iomem *plx_acc_32;
101262306a36Sopenharmony_ci	u_int	pv;
101362306a36Sopenharmony_ci	u_long	plx_flags;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
101662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: entered\n", __func__);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* soft reset also masks all interrupts */
101962306a36Sopenharmony_ci	hc->hw.r_cirm |= V_SRES;
102062306a36Sopenharmony_ci	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
102162306a36Sopenharmony_ci	udelay(1000);
102262306a36Sopenharmony_ci	hc->hw.r_cirm &= ~V_SRES;
102362306a36Sopenharmony_ci	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
102462306a36Sopenharmony_ci	udelay(1000); /* instead of 'wait' that may cause locking */
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	/* release Speech Design card, if PLX was initialized */
102762306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->plx_membase) {
102862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_PLXSD)
102962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: release PLXSD card %d\n",
103062306a36Sopenharmony_ci			       __func__, hc->id + 1);
103162306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
103262306a36Sopenharmony_ci		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
103362306a36Sopenharmony_ci		writel(PLX_GPIOC_INIT, plx_acc_32);
103462306a36Sopenharmony_ci		pv = readl(plx_acc_32);
103562306a36Sopenharmony_ci		/* Termination off */
103662306a36Sopenharmony_ci		pv &= ~PLX_TERM_ON;
103762306a36Sopenharmony_ci		/* Disconnect the PCM */
103862306a36Sopenharmony_ci		pv |= PLX_SLAVE_EN_N;
103962306a36Sopenharmony_ci		pv &= ~PLX_MASTER_EN;
104062306a36Sopenharmony_ci		pv &= ~PLX_SYNC_O_EN;
104162306a36Sopenharmony_ci		/* Put the DSP in Reset */
104262306a36Sopenharmony_ci		pv &= ~PLX_DSP_RES_N;
104362306a36Sopenharmony_ci		writel(pv, plx_acc_32);
104462306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
104562306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PCM off: PLX_GPIO=%x\n",
104662306a36Sopenharmony_ci			       __func__, pv);
104762306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	/* disable memory mapped ports / io ports */
105162306a36Sopenharmony_ci	test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */
105262306a36Sopenharmony_ci	if (hc->pci_dev)
105362306a36Sopenharmony_ci		pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
105462306a36Sopenharmony_ci	if (hc->pci_membase)
105562306a36Sopenharmony_ci		iounmap(hc->pci_membase);
105662306a36Sopenharmony_ci	if (hc->plx_membase)
105762306a36Sopenharmony_ci		iounmap(hc->plx_membase);
105862306a36Sopenharmony_ci	if (hc->pci_iobase)
105962306a36Sopenharmony_ci		release_region(hc->pci_iobase, 8);
106062306a36Sopenharmony_ci	if (hc->xhfc_membase)
106162306a36Sopenharmony_ci		iounmap((void *)hc->xhfc_membase);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (hc->pci_dev) {
106462306a36Sopenharmony_ci		pci_disable_device(hc->pci_dev);
106562306a36Sopenharmony_ci		pci_set_drvdata(hc->pci_dev, NULL);
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
106862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: done\n", __func__);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/*
107262306a36Sopenharmony_ci * function called to reset the HFC chip. A complete software reset of chip
107362306a36Sopenharmony_ci * and fifos is done. All configuration of the chip is done.
107462306a36Sopenharmony_ci */
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic int
107762306a36Sopenharmony_ciinit_chip(struct hfc_multi *hc)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	u_long			flags, val, val2 = 0, rev;
108062306a36Sopenharmony_ci	int			i, err = 0;
108162306a36Sopenharmony_ci	u_char			r_conf_en, rval;
108262306a36Sopenharmony_ci	void __iomem		*plx_acc_32;
108362306a36Sopenharmony_ci	u_int			pv;
108462306a36Sopenharmony_ci	u_long			plx_flags, hfc_flags;
108562306a36Sopenharmony_ci	int			plx_count;
108662306a36Sopenharmony_ci	struct hfc_multi	*pos, *next, *plx_last_hc;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
108962306a36Sopenharmony_ci	/* reset all registers */
109062306a36Sopenharmony_ci	memset(&hc->hw, 0, sizeof(struct hfcm_hw));
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	/* revision check */
109362306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
109462306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: entered\n", __func__);
109562306a36Sopenharmony_ci	val = HFC_inb(hc, R_CHIP_ID);
109662306a36Sopenharmony_ci	if ((val >> 4) != 0x8 && (val >> 4) != 0xc && (val >> 4) != 0xe &&
109762306a36Sopenharmony_ci	    (val >> 1) != 0x31) {
109862306a36Sopenharmony_ci		printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n", (u_int)val);
109962306a36Sopenharmony_ci		err = -EIO;
110062306a36Sopenharmony_ci		goto out;
110162306a36Sopenharmony_ci	}
110262306a36Sopenharmony_ci	rev = HFC_inb(hc, R_CHIP_RV);
110362306a36Sopenharmony_ci	printk(KERN_INFO
110462306a36Sopenharmony_ci	       "HFC_multi: detected HFC with chip ID=0x%lx revision=%ld%s\n",
110562306a36Sopenharmony_ci	       val, rev, (rev == 0 && (hc->ctype != HFC_TYPE_XHFC)) ?
110662306a36Sopenharmony_ci	       " (old FIFO handling)" : "");
110762306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_XHFC && rev == 0) {
110862306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip);
110962306a36Sopenharmony_ci		printk(KERN_WARNING
111062306a36Sopenharmony_ci		       "HFC_multi: NOTE: Your chip is revision 0, "
111162306a36Sopenharmony_ci		       "ask Cologne Chip for update. Newer chips "
111262306a36Sopenharmony_ci		       "have a better FIFO handling. Old chips "
111362306a36Sopenharmony_ci		       "still work but may have slightly lower "
111462306a36Sopenharmony_ci		       "HDLC transmit performance.\n");
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci	if (rev > 1) {
111762306a36Sopenharmony_ci		printk(KERN_WARNING "HFC_multi: WARNING: This driver doesn't "
111862306a36Sopenharmony_ci		       "consider chip revision = %ld. The chip / "
111962306a36Sopenharmony_ci		       "bridge may not work.\n", rev);
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* set s-ram size */
112362306a36Sopenharmony_ci	hc->Flen = 0x10;
112462306a36Sopenharmony_ci	hc->Zmin = 0x80;
112562306a36Sopenharmony_ci	hc->Zlen = 384;
112662306a36Sopenharmony_ci	hc->DTMFbase = 0x1000;
112762306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) {
112862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
112962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: changing to 128K external RAM\n",
113062306a36Sopenharmony_ci			       __func__);
113162306a36Sopenharmony_ci		hc->hw.r_ctrl |= V_EXT_RAM;
113262306a36Sopenharmony_ci		hc->hw.r_ram_sz = 1;
113362306a36Sopenharmony_ci		hc->Flen = 0x20;
113462306a36Sopenharmony_ci		hc->Zmin = 0xc0;
113562306a36Sopenharmony_ci		hc->Zlen = 1856;
113662306a36Sopenharmony_ci		hc->DTMFbase = 0x2000;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) {
113962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
114062306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: changing to 512K external RAM\n",
114162306a36Sopenharmony_ci			       __func__);
114262306a36Sopenharmony_ci		hc->hw.r_ctrl |= V_EXT_RAM;
114362306a36Sopenharmony_ci		hc->hw.r_ram_sz = 2;
114462306a36Sopenharmony_ci		hc->Flen = 0x20;
114562306a36Sopenharmony_ci		hc->Zmin = 0xc0;
114662306a36Sopenharmony_ci		hc->Zlen = 8000;
114762306a36Sopenharmony_ci		hc->DTMFbase = 0x2000;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_XHFC) {
115062306a36Sopenharmony_ci		hc->Flen = 0x8;
115162306a36Sopenharmony_ci		hc->Zmin = 0x0;
115262306a36Sopenharmony_ci		hc->Zlen = 64;
115362306a36Sopenharmony_ci		hc->DTMFbase = 0x0;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci	hc->max_trans = poll << 1;
115662306a36Sopenharmony_ci	if (hc->max_trans > hc->Zlen)
115762306a36Sopenharmony_ci		hc->max_trans = hc->Zlen;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/* Speech Design PLX bridge */
116062306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
116162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_PLXSD)
116262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: initializing PLXSD card %d\n",
116362306a36Sopenharmony_ci			       __func__, hc->id + 1);
116462306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
116562306a36Sopenharmony_ci		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
116662306a36Sopenharmony_ci		writel(PLX_GPIOC_INIT, plx_acc_32);
116762306a36Sopenharmony_ci		pv = readl(plx_acc_32);
116862306a36Sopenharmony_ci		/* The first and the last cards are terminating the PCM bus */
116962306a36Sopenharmony_ci		pv |= PLX_TERM_ON; /* hc is currently the last */
117062306a36Sopenharmony_ci		/* Disconnect the PCM */
117162306a36Sopenharmony_ci		pv |= PLX_SLAVE_EN_N;
117262306a36Sopenharmony_ci		pv &= ~PLX_MASTER_EN;
117362306a36Sopenharmony_ci		pv &= ~PLX_SYNC_O_EN;
117462306a36Sopenharmony_ci		/* Put the DSP in Reset */
117562306a36Sopenharmony_ci		pv &= ~PLX_DSP_RES_N;
117662306a36Sopenharmony_ci		writel(pv, plx_acc_32);
117762306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
117862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
117962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: slave/term: PLX_GPIO=%x\n",
118062306a36Sopenharmony_ci			       __func__, pv);
118162306a36Sopenharmony_ci		/*
118262306a36Sopenharmony_ci		 * If we are the 3rd PLXSD card or higher, we must turn
118362306a36Sopenharmony_ci		 * termination of last PLXSD card off.
118462306a36Sopenharmony_ci		 */
118562306a36Sopenharmony_ci		spin_lock_irqsave(&HFClock, hfc_flags);
118662306a36Sopenharmony_ci		plx_count = 0;
118762306a36Sopenharmony_ci		plx_last_hc = NULL;
118862306a36Sopenharmony_ci		list_for_each_entry_safe(pos, next, &HFClist, list) {
118962306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PLXSD, &pos->chip)) {
119062306a36Sopenharmony_ci				plx_count++;
119162306a36Sopenharmony_ci				if (pos != hc)
119262306a36Sopenharmony_ci					plx_last_hc = pos;
119362306a36Sopenharmony_ci			}
119462306a36Sopenharmony_ci		}
119562306a36Sopenharmony_ci		if (plx_count >= 3) {
119662306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
119762306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: card %d is between, so "
119862306a36Sopenharmony_ci				       "we disable termination\n",
119962306a36Sopenharmony_ci				       __func__, plx_last_hc->id + 1);
120062306a36Sopenharmony_ci			spin_lock_irqsave(&plx_lock, plx_flags);
120162306a36Sopenharmony_ci			plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC;
120262306a36Sopenharmony_ci			pv = readl(plx_acc_32);
120362306a36Sopenharmony_ci			pv &= ~PLX_TERM_ON;
120462306a36Sopenharmony_ci			writel(pv, plx_acc_32);
120562306a36Sopenharmony_ci			spin_unlock_irqrestore(&plx_lock, plx_flags);
120662306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
120762306a36Sopenharmony_ci				printk(KERN_DEBUG
120862306a36Sopenharmony_ci				       "%s: term off: PLX_GPIO=%x\n",
120962306a36Sopenharmony_ci				       __func__, pv);
121062306a36Sopenharmony_ci		}
121162306a36Sopenharmony_ci		spin_unlock_irqrestore(&HFClock, hfc_flags);
121262306a36Sopenharmony_ci		hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
121662306a36Sopenharmony_ci		hc->hw.r_pcm_md0 = V_F0_LEN; /* shift clock for DSP */
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	/* we only want the real Z2 read-pointer for revision > 0 */
121962306a36Sopenharmony_ci	if (!test_bit(HFC_CHIP_REVISION0, &hc->chip))
122062306a36Sopenharmony_ci		hc->hw.r_ram_sz |= V_FZ_MD;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	/* select pcm mode */
122362306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
122462306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
122562306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: setting PCM into slave mode\n",
122662306a36Sopenharmony_ci			       __func__);
122762306a36Sopenharmony_ci	} else
122862306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip) && !plxsd_master) {
122962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
123062306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: setting PCM into master mode\n",
123162306a36Sopenharmony_ci				       __func__);
123262306a36Sopenharmony_ci			hc->hw.r_pcm_md0 |= V_PCM_MD;
123362306a36Sopenharmony_ci		} else {
123462306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
123562306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: performing PCM auto detect\n",
123662306a36Sopenharmony_ci				       __func__);
123762306a36Sopenharmony_ci		}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* soft reset */
124062306a36Sopenharmony_ci	HFC_outb(hc, R_CTRL, hc->hw.r_ctrl);
124162306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_XHFC)
124262306a36Sopenharmony_ci		HFC_outb(hc, 0x0C /* R_FIFO_THRES */,
124362306a36Sopenharmony_ci			 0x11 /* 16 Bytes TX/RX */);
124462306a36Sopenharmony_ci	else
124562306a36Sopenharmony_ci		HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
124662306a36Sopenharmony_ci	HFC_outb(hc, R_FIFO_MD, 0);
124762306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_XHFC)
124862306a36Sopenharmony_ci		hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES;
124962306a36Sopenharmony_ci	else
125062306a36Sopenharmony_ci		hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES
125162306a36Sopenharmony_ci			| V_RLD_EPR;
125262306a36Sopenharmony_ci	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
125362306a36Sopenharmony_ci	udelay(100);
125462306a36Sopenharmony_ci	hc->hw.r_cirm = 0;
125562306a36Sopenharmony_ci	HFC_outb(hc, R_CIRM, hc->hw.r_cirm);
125662306a36Sopenharmony_ci	udelay(100);
125762306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_XHFC)
125862306a36Sopenharmony_ci		HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Speech Design PLX bridge pcm and sync mode */
126162306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
126262306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
126362306a36Sopenharmony_ci		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
126462306a36Sopenharmony_ci		pv = readl(plx_acc_32);
126562306a36Sopenharmony_ci		/* Connect PCM */
126662306a36Sopenharmony_ci		if (hc->hw.r_pcm_md0 & V_PCM_MD) {
126762306a36Sopenharmony_ci			pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
126862306a36Sopenharmony_ci			pv |= PLX_SYNC_O_EN;
126962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
127062306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: master: PLX_GPIO=%x\n",
127162306a36Sopenharmony_ci				       __func__, pv);
127262306a36Sopenharmony_ci		} else {
127362306a36Sopenharmony_ci			pv &= ~(PLX_MASTER_EN | PLX_SLAVE_EN_N);
127462306a36Sopenharmony_ci			pv &= ~PLX_SYNC_O_EN;
127562306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
127662306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: slave: PLX_GPIO=%x\n",
127762306a36Sopenharmony_ci				       __func__, pv);
127862306a36Sopenharmony_ci		}
127962306a36Sopenharmony_ci		writel(pv, plx_acc_32);
128062306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/* PCM setup */
128462306a36Sopenharmony_ci	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90);
128562306a36Sopenharmony_ci	if (hc->slots == 32)
128662306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD1, 0x00);
128762306a36Sopenharmony_ci	if (hc->slots == 64)
128862306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD1, 0x10);
128962306a36Sopenharmony_ci	if (hc->slots == 128)
129062306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD1, 0x20);
129162306a36Sopenharmony_ci	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0xa0);
129262306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
129362306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD2, V_SYNC_SRC); /* sync via SYNC_I / O */
129462306a36Sopenharmony_ci	else if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
129562306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD2, 0x10); /* V_C2O_EN */
129662306a36Sopenharmony_ci	else
129762306a36Sopenharmony_ci		HFC_outb(hc, R_PCM_MD2, 0x00); /* sync from interface */
129862306a36Sopenharmony_ci	HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
129962306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
130062306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_SLOT, i);
130162306a36Sopenharmony_ci		HFC_outb_nodebug(hc, A_SL_CFG, 0);
130262306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_XHFC)
130362306a36Sopenharmony_ci			HFC_outb_nodebug(hc, A_CONF, 0);
130462306a36Sopenharmony_ci		hc->slot_owner[i] = -1;
130562306a36Sopenharmony_ci	}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	/* set clock speed */
130862306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_CLOCK2, &hc->chip)) {
130962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
131062306a36Sopenharmony_ci			printk(KERN_DEBUG
131162306a36Sopenharmony_ci			       "%s: setting double clock\n", __func__);
131262306a36Sopenharmony_ci		HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_EMBSD, &hc->chip))
131662306a36Sopenharmony_ci		HFC_outb(hc, 0x02 /* R_CLK_CFG */, 0x40 /* V_CLKO_OFF */);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	/* B410P GPIO */
131962306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
132062306a36Sopenharmony_ci		printk(KERN_NOTICE "Setting GPIOs\n");
132162306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_SEL, 0x30);
132262306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_EN1, 0x3);
132362306a36Sopenharmony_ci		udelay(1000);
132462306a36Sopenharmony_ci		printk(KERN_NOTICE "calling vpm_init\n");
132562306a36Sopenharmony_ci		vpm_init(hc);
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	/* check if R_F0_CNT counts (8 kHz frame count) */
132962306a36Sopenharmony_ci	val = HFC_inb(hc, R_F0_CNTL);
133062306a36Sopenharmony_ci	val += HFC_inb(hc, R_F0_CNTH) << 8;
133162306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
133262306a36Sopenharmony_ci		printk(KERN_DEBUG
133362306a36Sopenharmony_ci		       "HFC_multi F0_CNT %ld after reset\n", val);
133462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
133562306a36Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
133662306a36Sopenharmony_ci	schedule_timeout((HZ / 100) ? : 1); /* Timeout minimum 10ms */
133762306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
133862306a36Sopenharmony_ci	val2 = HFC_inb(hc, R_F0_CNTL);
133962306a36Sopenharmony_ci	val2 += HFC_inb(hc, R_F0_CNTH) << 8;
134062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
134162306a36Sopenharmony_ci		printk(KERN_DEBUG
134262306a36Sopenharmony_ci		       "HFC_multi F0_CNT %ld after 10 ms (1st try)\n",
134362306a36Sopenharmony_ci		       val2);
134462306a36Sopenharmony_ci	if (val2 >= val + 8) { /* 1 ms */
134562306a36Sopenharmony_ci		/* it counts, so we keep the pcm mode */
134662306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
134762306a36Sopenharmony_ci			printk(KERN_INFO "controller is PCM bus MASTER\n");
134862306a36Sopenharmony_ci		else
134962306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip))
135062306a36Sopenharmony_ci				printk(KERN_INFO "controller is PCM bus SLAVE\n");
135162306a36Sopenharmony_ci			else {
135262306a36Sopenharmony_ci				test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
135362306a36Sopenharmony_ci				printk(KERN_INFO "controller is PCM bus SLAVE "
135462306a36Sopenharmony_ci				       "(auto detected)\n");
135562306a36Sopenharmony_ci			}
135662306a36Sopenharmony_ci	} else {
135762306a36Sopenharmony_ci		/* does not count */
135862306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) {
135962306a36Sopenharmony_ci		controller_fail:
136062306a36Sopenharmony_ci			printk(KERN_ERR "HFC_multi ERROR, getting no 125us "
136162306a36Sopenharmony_ci			       "pulse. Seems that controller fails.\n");
136262306a36Sopenharmony_ci			err = -EIO;
136362306a36Sopenharmony_ci			goto out;
136462306a36Sopenharmony_ci		}
136562306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
136662306a36Sopenharmony_ci			printk(KERN_INFO "controller is PCM bus SLAVE "
136762306a36Sopenharmony_ci			       "(ignoring missing PCM clock)\n");
136862306a36Sopenharmony_ci		} else {
136962306a36Sopenharmony_ci			/* only one pcm master */
137062306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
137162306a36Sopenharmony_ci			    && plxsd_master) {
137262306a36Sopenharmony_ci				printk(KERN_ERR "HFC_multi ERROR, no clock "
137362306a36Sopenharmony_ci				       "on another Speech Design card found. "
137462306a36Sopenharmony_ci				       "Please be sure to connect PCM cable.\n");
137562306a36Sopenharmony_ci				err = -EIO;
137662306a36Sopenharmony_ci				goto out;
137762306a36Sopenharmony_ci			}
137862306a36Sopenharmony_ci			/* retry with master clock */
137962306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
138062306a36Sopenharmony_ci				spin_lock_irqsave(&plx_lock, plx_flags);
138162306a36Sopenharmony_ci				plx_acc_32 = hc->plx_membase + PLX_GPIOC;
138262306a36Sopenharmony_ci				pv = readl(plx_acc_32);
138362306a36Sopenharmony_ci				pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
138462306a36Sopenharmony_ci				pv |= PLX_SYNC_O_EN;
138562306a36Sopenharmony_ci				writel(pv, plx_acc_32);
138662306a36Sopenharmony_ci				spin_unlock_irqrestore(&plx_lock, plx_flags);
138762306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_INIT)
138862306a36Sopenharmony_ci					printk(KERN_DEBUG "%s: master: "
138962306a36Sopenharmony_ci					       "PLX_GPIO=%x\n", __func__, pv);
139062306a36Sopenharmony_ci			}
139162306a36Sopenharmony_ci			hc->hw.r_pcm_md0 |= V_PCM_MD;
139262306a36Sopenharmony_ci			HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x00);
139362306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
139462306a36Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
139562306a36Sopenharmony_ci			schedule_timeout((HZ / 100) ?: 1); /* Timeout min. 10ms */
139662306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
139762306a36Sopenharmony_ci			val2 = HFC_inb(hc, R_F0_CNTL);
139862306a36Sopenharmony_ci			val2 += HFC_inb(hc, R_F0_CNTH) << 8;
139962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
140062306a36Sopenharmony_ci				printk(KERN_DEBUG "HFC_multi F0_CNT %ld after "
140162306a36Sopenharmony_ci				       "10 ms (2nd try)\n", val2);
140262306a36Sopenharmony_ci			if (val2 >= val + 8) { /* 1 ms */
140362306a36Sopenharmony_ci				test_and_set_bit(HFC_CHIP_PCM_MASTER,
140462306a36Sopenharmony_ci						 &hc->chip);
140562306a36Sopenharmony_ci				printk(KERN_INFO "controller is PCM bus MASTER "
140662306a36Sopenharmony_ci				       "(auto detected)\n");
140762306a36Sopenharmony_ci			} else
140862306a36Sopenharmony_ci				goto controller_fail;
140962306a36Sopenharmony_ci		}
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* Release the DSP Reset */
141362306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
141462306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
141562306a36Sopenharmony_ci			plxsd_master = 1;
141662306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
141762306a36Sopenharmony_ci		plx_acc_32 = hc->plx_membase + PLX_GPIOC;
141862306a36Sopenharmony_ci		pv = readl(plx_acc_32);
141962306a36Sopenharmony_ci		pv |=  PLX_DSP_RES_N;
142062306a36Sopenharmony_ci		writel(pv, plx_acc_32);
142162306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
142262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
142362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: reset off: PLX_GPIO=%x\n",
142462306a36Sopenharmony_ci			       __func__, pv);
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	/* pcm id */
142862306a36Sopenharmony_ci	if (hc->pcm)
142962306a36Sopenharmony_ci		printk(KERN_INFO "controller has given PCM BUS ID %d\n",
143062306a36Sopenharmony_ci		       hc->pcm);
143162306a36Sopenharmony_ci	else {
143262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)
143362306a36Sopenharmony_ci		    || test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
143462306a36Sopenharmony_ci			PCM_cnt++; /* SD has proprietary bridging */
143562306a36Sopenharmony_ci		}
143662306a36Sopenharmony_ci		hc->pcm = PCM_cnt;
143762306a36Sopenharmony_ci		printk(KERN_INFO "controller has PCM BUS ID %d "
143862306a36Sopenharmony_ci		       "(auto selected)\n", hc->pcm);
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	/* set up timer */
144262306a36Sopenharmony_ci	HFC_outb(hc, R_TI_WD, poll_timer);
144362306a36Sopenharmony_ci	hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	/* set E1 state machine IRQ */
144662306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1)
144762306a36Sopenharmony_ci		hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* set DTMF detection */
145062306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_DTMF, &hc->chip)) {
145162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
145262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: enabling DTMF detection "
145362306a36Sopenharmony_ci			       "for all B-channel\n", __func__);
145462306a36Sopenharmony_ci		hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP;
145562306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_ULAW, &hc->chip))
145662306a36Sopenharmony_ci			hc->hw.r_dtmf |= V_ULAW_SEL;
145762306a36Sopenharmony_ci		HFC_outb(hc, R_DTMF_N, 102 - 1);
145862306a36Sopenharmony_ci		hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	/* conference engine */
146262306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_ULAW, &hc->chip))
146362306a36Sopenharmony_ci		r_conf_en = V_CONF_EN | V_ULAW;
146462306a36Sopenharmony_ci	else
146562306a36Sopenharmony_ci		r_conf_en = V_CONF_EN;
146662306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_XHFC)
146762306a36Sopenharmony_ci		HFC_outb(hc, R_CONF_EN, r_conf_en);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	/* setting leds */
147062306a36Sopenharmony_ci	switch (hc->leds) {
147162306a36Sopenharmony_ci	case 1: /* HFC-E1 OEM */
147262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip))
147362306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_SEL, 0x32);
147462306a36Sopenharmony_ci		else
147562306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_SEL, 0x30);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_EN1, 0x0f);
147862306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_OUT1, 0x00);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
148162306a36Sopenharmony_ci		break;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	case 2: /* HFC-4S OEM */
148462306a36Sopenharmony_ci	case 3:
148562306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_SEL, 0xf0);
148662306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_EN1, 0xff);
148762306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_OUT1, 0x00);
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_EMBSD, &hc->chip)) {
149262306a36Sopenharmony_ci		hc->hw.r_st_sync = 0x10; /* V_AUTO_SYNCI */
149362306a36Sopenharmony_ci		HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	/* set master clock */
149762306a36Sopenharmony_ci	if (hc->masterclk >= 0) {
149862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
149962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: setting ST master clock "
150062306a36Sopenharmony_ci			       "to port %d (0..%d)\n",
150162306a36Sopenharmony_ci			       __func__, hc->masterclk, hc->ports - 1);
150262306a36Sopenharmony_ci		hc->hw.r_st_sync |= (hc->masterclk | V_AUTO_SYNC);
150362306a36Sopenharmony_ci		HFC_outb(hc, R_ST_SYNC, hc->hw.r_st_sync);
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* setting misc irq */
150962306a36Sopenharmony_ci	HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc);
151062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
151162306a36Sopenharmony_ci		printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n",
151262306a36Sopenharmony_ci		       hc->hw.r_irqmsk_misc);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* RAM access test */
151562306a36Sopenharmony_ci	HFC_outb(hc, R_RAM_ADDR0, 0);
151662306a36Sopenharmony_ci	HFC_outb(hc, R_RAM_ADDR1, 0);
151762306a36Sopenharmony_ci	HFC_outb(hc, R_RAM_ADDR2, 0);
151862306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
151962306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_RAM_ADDR0, i);
152062306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_RAM_DATA, ((i * 3) & 0xff));
152162306a36Sopenharmony_ci	}
152262306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
152362306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_RAM_ADDR0, i);
152462306a36Sopenharmony_ci		HFC_inb_nodebug(hc, R_RAM_DATA);
152562306a36Sopenharmony_ci		rval = HFC_inb_nodebug(hc, R_INT_DATA);
152662306a36Sopenharmony_ci		if (rval != ((i * 3) & 0xff)) {
152762306a36Sopenharmony_ci			printk(KERN_DEBUG
152862306a36Sopenharmony_ci			       "addr:%x val:%x should:%x\n", i, rval,
152962306a36Sopenharmony_ci			       (i * 3) & 0xff);
153062306a36Sopenharmony_ci			err++;
153162306a36Sopenharmony_ci		}
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci	if (err) {
153462306a36Sopenharmony_ci		printk(KERN_DEBUG "aborting - %d RAM access errors\n", err);
153562306a36Sopenharmony_ci		err = -EIO;
153662306a36Sopenharmony_ci		goto out;
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
154062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: done\n", __func__);
154162306a36Sopenharmony_ciout:
154262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
154362306a36Sopenharmony_ci	return err;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci/*
154862306a36Sopenharmony_ci * control the watchdog
154962306a36Sopenharmony_ci */
155062306a36Sopenharmony_cistatic void
155162306a36Sopenharmony_cihfcmulti_watchdog(struct hfc_multi *hc)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	hc->wdcount++;
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	if (hc->wdcount > 10) {
155662306a36Sopenharmony_ci		hc->wdcount = 0;
155762306a36Sopenharmony_ci		hc->wdbyte = hc->wdbyte == V_GPIO_OUT2 ?
155862306a36Sopenharmony_ci			V_GPIO_OUT3 : V_GPIO_OUT2;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci		/* printk("Sending Watchdog Kill %x\n",hc->wdbyte); */
156162306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_EN0, V_GPIO_EN2 | V_GPIO_EN3);
156262306a36Sopenharmony_ci		HFC_outb(hc, R_GPIO_OUT0, hc->wdbyte);
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci/*
156962306a36Sopenharmony_ci * output leds
157062306a36Sopenharmony_ci */
157162306a36Sopenharmony_cistatic void
157262306a36Sopenharmony_cihfcmulti_leds(struct hfc_multi *hc)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	unsigned long lled;
157562306a36Sopenharmony_ci	unsigned long leddw;
157662306a36Sopenharmony_ci	int i, state, active, leds;
157762306a36Sopenharmony_ci	struct dchannel *dch;
157862306a36Sopenharmony_ci	int led[4];
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	switch (hc->leds) {
158162306a36Sopenharmony_ci	case 1: /* HFC-E1 OEM */
158262306a36Sopenharmony_ci		/* 2 red steady:       LOS
158362306a36Sopenharmony_ci		 * 1 red steady:       L1 not active
158462306a36Sopenharmony_ci		 * 2 green steady:     L1 active
158562306a36Sopenharmony_ci		 * 1st green flashing: activity on TX
158662306a36Sopenharmony_ci		 * 2nd green flashing: activity on RX
158762306a36Sopenharmony_ci		 */
158862306a36Sopenharmony_ci		led[0] = 0;
158962306a36Sopenharmony_ci		led[1] = 0;
159062306a36Sopenharmony_ci		led[2] = 0;
159162306a36Sopenharmony_ci		led[3] = 0;
159262306a36Sopenharmony_ci		dch = hc->chan[hc->dnum[0]].dch;
159362306a36Sopenharmony_ci		if (dch) {
159462306a36Sopenharmony_ci			if (hc->chan[hc->dnum[0]].los)
159562306a36Sopenharmony_ci				led[1] = 1;
159662306a36Sopenharmony_ci			if (hc->e1_state != 1) {
159762306a36Sopenharmony_ci				led[0] = 1;
159862306a36Sopenharmony_ci				hc->flash[2] = 0;
159962306a36Sopenharmony_ci				hc->flash[3] = 0;
160062306a36Sopenharmony_ci			} else {
160162306a36Sopenharmony_ci				led[2] = 1;
160262306a36Sopenharmony_ci				led[3] = 1;
160362306a36Sopenharmony_ci				if (!hc->flash[2] && hc->activity_tx)
160462306a36Sopenharmony_ci					hc->flash[2] = poll;
160562306a36Sopenharmony_ci				if (!hc->flash[3] && hc->activity_rx)
160662306a36Sopenharmony_ci					hc->flash[3] = poll;
160762306a36Sopenharmony_ci				if (hc->flash[2] && hc->flash[2] < 1024)
160862306a36Sopenharmony_ci					led[2] = 0;
160962306a36Sopenharmony_ci				if (hc->flash[3] && hc->flash[3] < 1024)
161062306a36Sopenharmony_ci					led[3] = 0;
161162306a36Sopenharmony_ci				if (hc->flash[2] >= 2048)
161262306a36Sopenharmony_ci					hc->flash[2] = 0;
161362306a36Sopenharmony_ci				if (hc->flash[3] >= 2048)
161462306a36Sopenharmony_ci					hc->flash[3] = 0;
161562306a36Sopenharmony_ci				if (hc->flash[2])
161662306a36Sopenharmony_ci					hc->flash[2] += poll;
161762306a36Sopenharmony_ci				if (hc->flash[3])
161862306a36Sopenharmony_ci					hc->flash[3] += poll;
161962306a36Sopenharmony_ci			}
162062306a36Sopenharmony_ci		}
162162306a36Sopenharmony_ci		leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF;
162262306a36Sopenharmony_ci		/* leds are inverted */
162362306a36Sopenharmony_ci		if (leds != (int)hc->ledstate) {
162462306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_GPIO_OUT1, leds);
162562306a36Sopenharmony_ci			hc->ledstate = leds;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci		break;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	case 2: /* HFC-4S OEM */
163062306a36Sopenharmony_ci		/* red steady:     PH_DEACTIVATE
163162306a36Sopenharmony_ci		 * green steady:   PH_ACTIVATE
163262306a36Sopenharmony_ci		 * green flashing: activity on TX
163362306a36Sopenharmony_ci		 */
163462306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
163562306a36Sopenharmony_ci			state = 0;
163662306a36Sopenharmony_ci			active = -1;
163762306a36Sopenharmony_ci			dch = hc->chan[(i << 2) | 2].dch;
163862306a36Sopenharmony_ci			if (dch) {
163962306a36Sopenharmony_ci				state = dch->state;
164062306a36Sopenharmony_ci				if (dch->dev.D.protocol == ISDN_P_NT_S0)
164162306a36Sopenharmony_ci					active = 3;
164262306a36Sopenharmony_ci				else
164362306a36Sopenharmony_ci					active = 7;
164462306a36Sopenharmony_ci			}
164562306a36Sopenharmony_ci			if (state) {
164662306a36Sopenharmony_ci				if (state == active) {
164762306a36Sopenharmony_ci					led[i] = 1; /* led green */
164862306a36Sopenharmony_ci					hc->activity_tx |= hc->activity_rx;
164962306a36Sopenharmony_ci					if (!hc->flash[i] &&
165062306a36Sopenharmony_ci						(hc->activity_tx & (1 << i)))
165162306a36Sopenharmony_ci							hc->flash[i] = poll;
165262306a36Sopenharmony_ci					if (hc->flash[i] && hc->flash[i] < 1024)
165362306a36Sopenharmony_ci						led[i] = 0; /* led off */
165462306a36Sopenharmony_ci					if (hc->flash[i] >= 2048)
165562306a36Sopenharmony_ci						hc->flash[i] = 0;
165662306a36Sopenharmony_ci					if (hc->flash[i])
165762306a36Sopenharmony_ci						hc->flash[i] += poll;
165862306a36Sopenharmony_ci				} else {
165962306a36Sopenharmony_ci					led[i] = 2; /* led red */
166062306a36Sopenharmony_ci					hc->flash[i] = 0;
166162306a36Sopenharmony_ci				}
166262306a36Sopenharmony_ci			} else
166362306a36Sopenharmony_ci				led[i] = 0; /* led off */
166462306a36Sopenharmony_ci		}
166562306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
166662306a36Sopenharmony_ci			leds = 0;
166762306a36Sopenharmony_ci			for (i = 0; i < 4; i++) {
166862306a36Sopenharmony_ci				if (led[i] == 1) {
166962306a36Sopenharmony_ci					/*green*/
167062306a36Sopenharmony_ci					leds |= (0x2 << (i * 2));
167162306a36Sopenharmony_ci				} else if (led[i] == 2) {
167262306a36Sopenharmony_ci					/*red*/
167362306a36Sopenharmony_ci					leds |= (0x1 << (i * 2));
167462306a36Sopenharmony_ci				}
167562306a36Sopenharmony_ci			}
167662306a36Sopenharmony_ci			if (leds != (int)hc->ledstate) {
167762306a36Sopenharmony_ci				vpm_out(hc, 0, 0x1a8 + 3, leds);
167862306a36Sopenharmony_ci				hc->ledstate = leds;
167962306a36Sopenharmony_ci			}
168062306a36Sopenharmony_ci		} else {
168162306a36Sopenharmony_ci			leds = ((led[3] > 0) << 0) | ((led[1] > 0) << 1) |
168262306a36Sopenharmony_ci				((led[0] > 0) << 2) | ((led[2] > 0) << 3) |
168362306a36Sopenharmony_ci				((led[3] & 1) << 4) | ((led[1] & 1) << 5) |
168462306a36Sopenharmony_ci				((led[0] & 1) << 6) | ((led[2] & 1) << 7);
168562306a36Sopenharmony_ci			if (leds != (int)hc->ledstate) {
168662306a36Sopenharmony_ci				HFC_outb_nodebug(hc, R_GPIO_EN1, leds & 0x0F);
168762306a36Sopenharmony_ci				HFC_outb_nodebug(hc, R_GPIO_OUT1, leds >> 4);
168862306a36Sopenharmony_ci				hc->ledstate = leds;
168962306a36Sopenharmony_ci			}
169062306a36Sopenharmony_ci		}
169162306a36Sopenharmony_ci		break;
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	case 3: /* HFC 1S/2S Beronet */
169462306a36Sopenharmony_ci		/* red steady:     PH_DEACTIVATE
169562306a36Sopenharmony_ci		 * green steady:   PH_ACTIVATE
169662306a36Sopenharmony_ci		 * green flashing: activity on TX
169762306a36Sopenharmony_ci		 */
169862306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
169962306a36Sopenharmony_ci			state = 0;
170062306a36Sopenharmony_ci			active = -1;
170162306a36Sopenharmony_ci			dch = hc->chan[(i << 2) | 2].dch;
170262306a36Sopenharmony_ci			if (dch) {
170362306a36Sopenharmony_ci				state = dch->state;
170462306a36Sopenharmony_ci				if (dch->dev.D.protocol == ISDN_P_NT_S0)
170562306a36Sopenharmony_ci					active = 3;
170662306a36Sopenharmony_ci				else
170762306a36Sopenharmony_ci					active = 7;
170862306a36Sopenharmony_ci			}
170962306a36Sopenharmony_ci			if (state) {
171062306a36Sopenharmony_ci				if (state == active) {
171162306a36Sopenharmony_ci					led[i] = 1; /* led green */
171262306a36Sopenharmony_ci					hc->activity_tx |= hc->activity_rx;
171362306a36Sopenharmony_ci					if (!hc->flash[i] &&
171462306a36Sopenharmony_ci						(hc->activity_tx & (1 << i)))
171562306a36Sopenharmony_ci							hc->flash[i] = poll;
171662306a36Sopenharmony_ci					if (hc->flash[i] < 1024)
171762306a36Sopenharmony_ci						led[i] = 0; /* led off */
171862306a36Sopenharmony_ci					if (hc->flash[i] >= 2048)
171962306a36Sopenharmony_ci						hc->flash[i] = 0;
172062306a36Sopenharmony_ci					if (hc->flash[i])
172162306a36Sopenharmony_ci						hc->flash[i] += poll;
172262306a36Sopenharmony_ci				} else {
172362306a36Sopenharmony_ci					led[i] = 2; /* led red */
172462306a36Sopenharmony_ci					hc->flash[i] = 0;
172562306a36Sopenharmony_ci				}
172662306a36Sopenharmony_ci			} else
172762306a36Sopenharmony_ci				led[i] = 0; /* led off */
172862306a36Sopenharmony_ci		}
172962306a36Sopenharmony_ci		leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2)
173062306a36Sopenharmony_ci			| ((led[1]&1) << 3);
173162306a36Sopenharmony_ci		if (leds != (int)hc->ledstate) {
173262306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_GPIO_EN1,
173362306a36Sopenharmony_ci					 ((led[0] > 0) << 2) | ((led[1] > 0) << 3));
173462306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_GPIO_OUT1,
173562306a36Sopenharmony_ci					 ((led[0] & 1) << 2) | ((led[1] & 1) << 3));
173662306a36Sopenharmony_ci			hc->ledstate = leds;
173762306a36Sopenharmony_ci		}
173862306a36Sopenharmony_ci		break;
173962306a36Sopenharmony_ci	case 8: /* HFC 8S+ Beronet */
174062306a36Sopenharmony_ci		/* off:      PH_DEACTIVATE
174162306a36Sopenharmony_ci		 * steady:   PH_ACTIVATE
174262306a36Sopenharmony_ci		 * flashing: activity on TX
174362306a36Sopenharmony_ci		 */
174462306a36Sopenharmony_ci		lled = 0xff; /* leds off */
174562306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
174662306a36Sopenharmony_ci			state = 0;
174762306a36Sopenharmony_ci			active = -1;
174862306a36Sopenharmony_ci			dch = hc->chan[(i << 2) | 2].dch;
174962306a36Sopenharmony_ci			if (dch) {
175062306a36Sopenharmony_ci				state = dch->state;
175162306a36Sopenharmony_ci				if (dch->dev.D.protocol == ISDN_P_NT_S0)
175262306a36Sopenharmony_ci					active = 3;
175362306a36Sopenharmony_ci				else
175462306a36Sopenharmony_ci					active = 7;
175562306a36Sopenharmony_ci			}
175662306a36Sopenharmony_ci			if (state) {
175762306a36Sopenharmony_ci				if (state == active) {
175862306a36Sopenharmony_ci					lled &= ~(1 << i); /* led on */
175962306a36Sopenharmony_ci					hc->activity_tx |= hc->activity_rx;
176062306a36Sopenharmony_ci					if (!hc->flash[i] &&
176162306a36Sopenharmony_ci						(hc->activity_tx & (1 << i)))
176262306a36Sopenharmony_ci							hc->flash[i] = poll;
176362306a36Sopenharmony_ci					if (hc->flash[i] < 1024)
176462306a36Sopenharmony_ci						lled |= 1 << i; /* led off */
176562306a36Sopenharmony_ci					if (hc->flash[i] >= 2048)
176662306a36Sopenharmony_ci						hc->flash[i] = 0;
176762306a36Sopenharmony_ci					if (hc->flash[i])
176862306a36Sopenharmony_ci						hc->flash[i] += poll;
176962306a36Sopenharmony_ci				} else
177062306a36Sopenharmony_ci					hc->flash[i] = 0;
177162306a36Sopenharmony_ci			}
177262306a36Sopenharmony_ci		}
177362306a36Sopenharmony_ci		leddw = lled << 24 | lled << 16 | lled << 8 | lled;
177462306a36Sopenharmony_ci		if (leddw != hc->ledstate) {
177562306a36Sopenharmony_ci			/* HFC_outb(hc, R_BRG_PCM_CFG, 1);
177662306a36Sopenharmony_ci			   HFC_outb(c, R_BRG_PCM_CFG, (0x0 << 6) | 0x3); */
177762306a36Sopenharmony_ci			/* was _io before */
177862306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
177962306a36Sopenharmony_ci			outw(0x4000, hc->pci_iobase + 4);
178062306a36Sopenharmony_ci			outl(leddw, hc->pci_iobase);
178162306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_BRG_PCM_CFG, V_PCM_CLK);
178262306a36Sopenharmony_ci			hc->ledstate = leddw;
178362306a36Sopenharmony_ci		}
178462306a36Sopenharmony_ci		break;
178562306a36Sopenharmony_ci	}
178662306a36Sopenharmony_ci	hc->activity_tx = 0;
178762306a36Sopenharmony_ci	hc->activity_rx = 0;
178862306a36Sopenharmony_ci}
178962306a36Sopenharmony_ci/*
179062306a36Sopenharmony_ci * read dtmf coefficients
179162306a36Sopenharmony_ci */
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_cistatic void
179462306a36Sopenharmony_cihfcmulti_dtmf(struct hfc_multi *hc)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	s32		*coeff;
179762306a36Sopenharmony_ci	u_int		mantissa;
179862306a36Sopenharmony_ci	int		co, ch;
179962306a36Sopenharmony_ci	struct bchannel	*bch = NULL;
180062306a36Sopenharmony_ci	u8		exponent;
180162306a36Sopenharmony_ci	int		dtmf = 0;
180262306a36Sopenharmony_ci	int		addr;
180362306a36Sopenharmony_ci	u16		w_float;
180462306a36Sopenharmony_ci	struct sk_buff	*skb;
180562306a36Sopenharmony_ci	struct mISDNhead *hh;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_DTMF)
180862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: dtmf detection irq\n", __func__);
180962306a36Sopenharmony_ci	for (ch = 0; ch <= 31; ch++) {
181062306a36Sopenharmony_ci		/* only process enabled B-channels */
181162306a36Sopenharmony_ci		bch = hc->chan[ch].bch;
181262306a36Sopenharmony_ci		if (!bch)
181362306a36Sopenharmony_ci			continue;
181462306a36Sopenharmony_ci		if (!hc->created[hc->chan[ch].port])
181562306a36Sopenharmony_ci			continue;
181662306a36Sopenharmony_ci		if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
181762306a36Sopenharmony_ci			continue;
181862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_DTMF)
181962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: dtmf channel %d:",
182062306a36Sopenharmony_ci			       __func__, ch);
182162306a36Sopenharmony_ci		coeff = &(hc->chan[ch].coeff[hc->chan[ch].coeff_count * 16]);
182262306a36Sopenharmony_ci		dtmf = 1;
182362306a36Sopenharmony_ci		for (co = 0; co < 8; co++) {
182462306a36Sopenharmony_ci			/* read W(n-1) coefficient */
182562306a36Sopenharmony_ci			addr = hc->DTMFbase + ((co << 7) | (ch << 2));
182662306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_RAM_ADDR0, addr);
182762306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_RAM_ADDR1, addr >> 8);
182862306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_RAM_ADDR2, (addr >> 16)
182962306a36Sopenharmony_ci					 | V_ADDR_INC);
183062306a36Sopenharmony_ci			w_float = HFC_inb_nodebug(hc, R_RAM_DATA);
183162306a36Sopenharmony_ci			w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8);
183262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_DTMF)
183362306a36Sopenharmony_ci				printk(" %04x", w_float);
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci			/* decode float (see chip doc) */
183662306a36Sopenharmony_ci			mantissa = w_float & 0x0fff;
183762306a36Sopenharmony_ci			if (w_float & 0x8000)
183862306a36Sopenharmony_ci				mantissa |= 0xfffff000;
183962306a36Sopenharmony_ci			exponent = (w_float >> 12) & 0x7;
184062306a36Sopenharmony_ci			if (exponent) {
184162306a36Sopenharmony_ci				mantissa ^= 0x1000;
184262306a36Sopenharmony_ci				mantissa <<= (exponent - 1);
184362306a36Sopenharmony_ci			}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci			/* store coefficient */
184662306a36Sopenharmony_ci			coeff[co << 1] = mantissa;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci			/* read W(n) coefficient */
184962306a36Sopenharmony_ci			w_float = HFC_inb_nodebug(hc, R_RAM_DATA);
185062306a36Sopenharmony_ci			w_float |= (HFC_inb_nodebug(hc, R_RAM_DATA) << 8);
185162306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_DTMF)
185262306a36Sopenharmony_ci				printk(" %04x", w_float);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci			/* decode float (see chip doc) */
185562306a36Sopenharmony_ci			mantissa = w_float & 0x0fff;
185662306a36Sopenharmony_ci			if (w_float & 0x8000)
185762306a36Sopenharmony_ci				mantissa |= 0xfffff000;
185862306a36Sopenharmony_ci			exponent = (w_float >> 12) & 0x7;
185962306a36Sopenharmony_ci			if (exponent) {
186062306a36Sopenharmony_ci				mantissa ^= 0x1000;
186162306a36Sopenharmony_ci				mantissa <<= (exponent - 1);
186262306a36Sopenharmony_ci			}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci			/* store coefficient */
186562306a36Sopenharmony_ci			coeff[(co << 1) | 1] = mantissa;
186662306a36Sopenharmony_ci		}
186762306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_DTMF)
186862306a36Sopenharmony_ci			printk(" DTMF ready %08x %08x %08x %08x "
186962306a36Sopenharmony_ci			       "%08x %08x %08x %08x\n",
187062306a36Sopenharmony_ci			       coeff[0], coeff[1], coeff[2], coeff[3],
187162306a36Sopenharmony_ci			       coeff[4], coeff[5], coeff[6], coeff[7]);
187262306a36Sopenharmony_ci		hc->chan[ch].coeff_count++;
187362306a36Sopenharmony_ci		if (hc->chan[ch].coeff_count == 8) {
187462306a36Sopenharmony_ci			hc->chan[ch].coeff_count = 0;
187562306a36Sopenharmony_ci			skb = mI_alloc_skb(512, GFP_ATOMIC);
187662306a36Sopenharmony_ci			if (!skb) {
187762306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: No memory for skb\n",
187862306a36Sopenharmony_ci				       __func__);
187962306a36Sopenharmony_ci				continue;
188062306a36Sopenharmony_ci			}
188162306a36Sopenharmony_ci			hh = mISDN_HEAD_P(skb);
188262306a36Sopenharmony_ci			hh->prim = PH_CONTROL_IND;
188362306a36Sopenharmony_ci			hh->id = DTMF_HFC_COEF;
188462306a36Sopenharmony_ci			skb_put_data(skb, hc->chan[ch].coeff, 512);
188562306a36Sopenharmony_ci			recv_Bchannel_skb(bch, skb);
188662306a36Sopenharmony_ci		}
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* restart DTMF processing */
189062306a36Sopenharmony_ci	hc->dtmf = dtmf;
189162306a36Sopenharmony_ci	if (dtmf)
189262306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF);
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci/*
189762306a36Sopenharmony_ci * fill fifo as much as possible
189862306a36Sopenharmony_ci */
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_cistatic void
190162306a36Sopenharmony_cihfcmulti_tx(struct hfc_multi *hc, int ch)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	int i, ii, temp, len = 0;
190462306a36Sopenharmony_ci	int Zspace, z1, z2; /* must be int for calculation */
190562306a36Sopenharmony_ci	int Fspace, f1, f2;
190662306a36Sopenharmony_ci	u_char *d;
190762306a36Sopenharmony_ci	int *txpending, slot_tx;
190862306a36Sopenharmony_ci	struct	bchannel *bch;
190962306a36Sopenharmony_ci	struct  dchannel *dch;
191062306a36Sopenharmony_ci	struct  sk_buff **sp = NULL;
191162306a36Sopenharmony_ci	int *idxp;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	bch = hc->chan[ch].bch;
191462306a36Sopenharmony_ci	dch = hc->chan[ch].dch;
191562306a36Sopenharmony_ci	if ((!dch) && (!bch))
191662306a36Sopenharmony_ci		return;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	txpending = &hc->chan[ch].txpending;
191962306a36Sopenharmony_ci	slot_tx = hc->chan[ch].slot_tx;
192062306a36Sopenharmony_ci	if (dch) {
192162306a36Sopenharmony_ci		if (!test_bit(FLG_ACTIVE, &dch->Flags))
192262306a36Sopenharmony_ci			return;
192362306a36Sopenharmony_ci		sp = &dch->tx_skb;
192462306a36Sopenharmony_ci		idxp = &dch->tx_idx;
192562306a36Sopenharmony_ci	} else {
192662306a36Sopenharmony_ci		if (!test_bit(FLG_ACTIVE, &bch->Flags))
192762306a36Sopenharmony_ci			return;
192862306a36Sopenharmony_ci		sp = &bch->tx_skb;
192962306a36Sopenharmony_ci		idxp = &bch->tx_idx;
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci	if (*sp)
193262306a36Sopenharmony_ci		len = (*sp)->len;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if ((!len) && *txpending != 1)
193562306a36Sopenharmony_ci		return; /* no data */
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
193862306a36Sopenharmony_ci	    (hc->chan[ch].protocol == ISDN_P_B_RAW) &&
193962306a36Sopenharmony_ci	    (hc->chan[ch].slot_rx < 0) &&
194062306a36Sopenharmony_ci	    (hc->chan[ch].slot_tx < 0))
194162306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1));
194262306a36Sopenharmony_ci	else
194362306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, ch << 1);
194462306a36Sopenharmony_ci	HFC_wait_nodebug(hc);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	if (*txpending == 2) {
194762306a36Sopenharmony_ci		/* reset fifo */
194862306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
194962306a36Sopenharmony_ci		HFC_wait_nodebug(hc);
195062306a36Sopenharmony_ci		HFC_outb(hc, A_SUBCH_CFG, 0);
195162306a36Sopenharmony_ci		*txpending = 1;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_cinext_frame:
195462306a36Sopenharmony_ci	if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
195562306a36Sopenharmony_ci		f1 = HFC_inb_nodebug(hc, A_F1);
195662306a36Sopenharmony_ci		f2 = HFC_inb_nodebug(hc, A_F2);
195762306a36Sopenharmony_ci		while (f2 != (temp = HFC_inb_nodebug(hc, A_F2))) {
195862306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_FIFO)
195962306a36Sopenharmony_ci				printk(KERN_DEBUG
196062306a36Sopenharmony_ci				       "%s(card %d): reread f2 because %d!=%d\n",
196162306a36Sopenharmony_ci				       __func__, hc->id + 1, temp, f2);
196262306a36Sopenharmony_ci			f2 = temp; /* repeat until F2 is equal */
196362306a36Sopenharmony_ci		}
196462306a36Sopenharmony_ci		Fspace = f2 - f1 - 1;
196562306a36Sopenharmony_ci		if (Fspace < 0)
196662306a36Sopenharmony_ci			Fspace += hc->Flen;
196762306a36Sopenharmony_ci		/*
196862306a36Sopenharmony_ci		 * Old FIFO handling doesn't give us the current Z2 read
196962306a36Sopenharmony_ci		 * pointer, so we cannot send the next frame before the fifo
197062306a36Sopenharmony_ci		 * is empty. It makes no difference except for a slightly
197162306a36Sopenharmony_ci		 * lower performance.
197262306a36Sopenharmony_ci		 */
197362306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_REVISION0, &hc->chip)) {
197462306a36Sopenharmony_ci			if (f1 != f2)
197562306a36Sopenharmony_ci				Fspace = 0;
197662306a36Sopenharmony_ci			else
197762306a36Sopenharmony_ci				Fspace = 1;
197862306a36Sopenharmony_ci		}
197962306a36Sopenharmony_ci		/* one frame only for ST D-channels, to allow resending */
198062306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_E1 && dch) {
198162306a36Sopenharmony_ci			if (f1 != f2)
198262306a36Sopenharmony_ci				Fspace = 0;
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci		/* F-counter full condition */
198562306a36Sopenharmony_ci		if (Fspace == 0)
198662306a36Sopenharmony_ci			return;
198762306a36Sopenharmony_ci	}
198862306a36Sopenharmony_ci	z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin;
198962306a36Sopenharmony_ci	z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin;
199062306a36Sopenharmony_ci	while (z2 != (temp = (HFC_inw_nodebug(hc, A_Z2) - hc->Zmin))) {
199162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_FIFO)
199262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s(card %d): reread z2 because "
199362306a36Sopenharmony_ci			       "%d!=%d\n", __func__, hc->id + 1, temp, z2);
199462306a36Sopenharmony_ci		z2 = temp; /* repeat unti Z2 is equal */
199562306a36Sopenharmony_ci	}
199662306a36Sopenharmony_ci	hc->chan[ch].Zfill = z1 - z2;
199762306a36Sopenharmony_ci	if (hc->chan[ch].Zfill < 0)
199862306a36Sopenharmony_ci		hc->chan[ch].Zfill += hc->Zlen;
199962306a36Sopenharmony_ci	Zspace = z2 - z1;
200062306a36Sopenharmony_ci	if (Zspace <= 0)
200162306a36Sopenharmony_ci		Zspace += hc->Zlen;
200262306a36Sopenharmony_ci	Zspace -= 4; /* keep not too full, so pointers will not overrun */
200362306a36Sopenharmony_ci	/* fill transparent data only to maxinum transparent load (minus 4) */
200462306a36Sopenharmony_ci	if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
200562306a36Sopenharmony_ci		Zspace = Zspace - hc->Zlen + hc->max_trans;
200662306a36Sopenharmony_ci	if (Zspace <= 0) /* no space of 4 bytes */
200762306a36Sopenharmony_ci		return;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	/* if no data */
201062306a36Sopenharmony_ci	if (!len) {
201162306a36Sopenharmony_ci		if (z1 == z2) { /* empty */
201262306a36Sopenharmony_ci			/* if done with FIFO audio data during PCM connection */
201362306a36Sopenharmony_ci			if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) &&
201462306a36Sopenharmony_ci			    *txpending && slot_tx >= 0) {
201562306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_MODE)
201662306a36Sopenharmony_ci					printk(KERN_DEBUG
201762306a36Sopenharmony_ci					       "%s: reconnecting PCM due to no "
201862306a36Sopenharmony_ci					       "more FIFO data: channel %d "
201962306a36Sopenharmony_ci					       "slot_tx %d\n",
202062306a36Sopenharmony_ci					       __func__, ch, slot_tx);
202162306a36Sopenharmony_ci				/* connect slot */
202262306a36Sopenharmony_ci				if (hc->ctype == HFC_TYPE_XHFC)
202362306a36Sopenharmony_ci					HFC_outb(hc, A_CON_HDLC, 0xc0
202462306a36Sopenharmony_ci						 | 0x07 << 2 | V_HDLC_TRP | V_IFF);
202562306a36Sopenharmony_ci				/* Enable FIFO, no interrupt */
202662306a36Sopenharmony_ci				else
202762306a36Sopenharmony_ci					HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
202862306a36Sopenharmony_ci						 V_HDLC_TRP | V_IFF);
202962306a36Sopenharmony_ci				HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1);
203062306a36Sopenharmony_ci				HFC_wait_nodebug(hc);
203162306a36Sopenharmony_ci				if (hc->ctype == HFC_TYPE_XHFC)
203262306a36Sopenharmony_ci					HFC_outb(hc, A_CON_HDLC, 0xc0
203362306a36Sopenharmony_ci						 | 0x07 << 2 | V_HDLC_TRP | V_IFF);
203462306a36Sopenharmony_ci				/* Enable FIFO, no interrupt */
203562306a36Sopenharmony_ci				else
203662306a36Sopenharmony_ci					HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 |
203762306a36Sopenharmony_ci						 V_HDLC_TRP | V_IFF);
203862306a36Sopenharmony_ci				HFC_outb_nodebug(hc, R_FIFO, ch << 1);
203962306a36Sopenharmony_ci				HFC_wait_nodebug(hc);
204062306a36Sopenharmony_ci			}
204162306a36Sopenharmony_ci			*txpending = 0;
204262306a36Sopenharmony_ci		}
204362306a36Sopenharmony_ci		return; /* no data */
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	/* "fill fifo if empty" feature */
204762306a36Sopenharmony_ci	if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags)
204862306a36Sopenharmony_ci	    && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) {
204962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_FILL)
205062306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: buffer empty, so we have "
205162306a36Sopenharmony_ci			       "underrun\n", __func__);
205262306a36Sopenharmony_ci		/* fill buffer, to prevent future underrun */
205362306a36Sopenharmony_ci		hc->write_fifo(hc, hc->silence_data, poll >> 1);
205462306a36Sopenharmony_ci		Zspace -= (poll >> 1);
205562306a36Sopenharmony_ci	}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* if audio data and connected slot */
205862306a36Sopenharmony_ci	if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending)
205962306a36Sopenharmony_ci	    && slot_tx >= 0) {
206062306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
206162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: disconnecting PCM due to "
206262306a36Sopenharmony_ci			       "FIFO data: channel %d slot_tx %d\n",
206362306a36Sopenharmony_ci			       __func__, ch, slot_tx);
206462306a36Sopenharmony_ci		/* disconnect slot */
206562306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_XHFC)
206662306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x80
206762306a36Sopenharmony_ci				 | 0x07 << 2 | V_HDLC_TRP | V_IFF);
206862306a36Sopenharmony_ci		/* Enable FIFO, no interrupt */
206962306a36Sopenharmony_ci		else
207062306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
207162306a36Sopenharmony_ci				 V_HDLC_TRP | V_IFF);
207262306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, ch << 1 | 1);
207362306a36Sopenharmony_ci		HFC_wait_nodebug(hc);
207462306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_XHFC)
207562306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x80
207662306a36Sopenharmony_ci				 | 0x07 << 2 | V_HDLC_TRP | V_IFF);
207762306a36Sopenharmony_ci		/* Enable FIFO, no interrupt */
207862306a36Sopenharmony_ci		else
207962306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 |
208062306a36Sopenharmony_ci				 V_HDLC_TRP | V_IFF);
208162306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, ch << 1);
208262306a36Sopenharmony_ci		HFC_wait_nodebug(hc);
208362306a36Sopenharmony_ci	}
208462306a36Sopenharmony_ci	*txpending = 1;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	/* show activity */
208762306a36Sopenharmony_ci	if (dch)
208862306a36Sopenharmony_ci		hc->activity_tx |= 1 << hc->chan[ch].port;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	/* fill fifo to what we have left */
209162306a36Sopenharmony_ci	ii = len;
209262306a36Sopenharmony_ci	if (dch || test_bit(FLG_HDLC, &bch->Flags))
209362306a36Sopenharmony_ci		temp = 1;
209462306a36Sopenharmony_ci	else
209562306a36Sopenharmony_ci		temp = 0;
209662306a36Sopenharmony_ci	i = *idxp;
209762306a36Sopenharmony_ci	d = (*sp)->data + i;
209862306a36Sopenharmony_ci	if (ii - i > Zspace)
209962306a36Sopenharmony_ci		ii = Zspace + i;
210062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_FIFO)
210162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space "
210262306a36Sopenharmony_ci		       "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n",
210362306a36Sopenharmony_ci		       __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
210462306a36Sopenharmony_ci		       temp ? "HDLC" : "TRANS");
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	/* Have to prep the audio data */
210762306a36Sopenharmony_ci	hc->write_fifo(hc, d, ii - i);
210862306a36Sopenharmony_ci	hc->chan[ch].Zfill += ii - i;
210962306a36Sopenharmony_ci	*idxp = ii;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* if not all data has been written */
211262306a36Sopenharmony_ci	if (ii != len) {
211362306a36Sopenharmony_ci		/* NOTE: fifo is started by the calling function */
211462306a36Sopenharmony_ci		return;
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	/* if all data has been written, terminate frame */
211862306a36Sopenharmony_ci	if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
211962306a36Sopenharmony_ci		/* increment f-counter */
212062306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
212162306a36Sopenharmony_ci		HFC_wait_nodebug(hc);
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	dev_kfree_skb(*sp);
212562306a36Sopenharmony_ci	/* check for next frame */
212662306a36Sopenharmony_ci	if (bch && get_next_bframe(bch)) {
212762306a36Sopenharmony_ci		len = (*sp)->len;
212862306a36Sopenharmony_ci		goto next_frame;
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci	if (dch && get_next_dframe(dch)) {
213162306a36Sopenharmony_ci		len = (*sp)->len;
213262306a36Sopenharmony_ci		goto next_frame;
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/*
213662306a36Sopenharmony_ci	 * now we have no more data, so in case of transparent,
213762306a36Sopenharmony_ci	 * we set the last byte in fifo to 'silence' in case we will get
213862306a36Sopenharmony_ci	 * no more data at all. this prevents sending an undefined value.
213962306a36Sopenharmony_ci	 */
214062306a36Sopenharmony_ci	if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
214162306a36Sopenharmony_ci		HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci/* NOTE: only called if E1 card is in active state */
214662306a36Sopenharmony_cistatic void
214762306a36Sopenharmony_cihfcmulti_rx(struct hfc_multi *hc, int ch)
214862306a36Sopenharmony_ci{
214962306a36Sopenharmony_ci	int temp;
215062306a36Sopenharmony_ci	int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */
215162306a36Sopenharmony_ci	int f1 = 0, f2 = 0; /* = 0, to make GCC happy */
215262306a36Sopenharmony_ci	int again = 0;
215362306a36Sopenharmony_ci	struct	bchannel *bch;
215462306a36Sopenharmony_ci	struct  dchannel *dch = NULL;
215562306a36Sopenharmony_ci	struct sk_buff	*skb, **sp = NULL;
215662306a36Sopenharmony_ci	int	maxlen;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	bch = hc->chan[ch].bch;
215962306a36Sopenharmony_ci	if (bch) {
216062306a36Sopenharmony_ci		if (!test_bit(FLG_ACTIVE, &bch->Flags))
216162306a36Sopenharmony_ci			return;
216262306a36Sopenharmony_ci	} else if (hc->chan[ch].dch) {
216362306a36Sopenharmony_ci		dch = hc->chan[ch].dch;
216462306a36Sopenharmony_ci		if (!test_bit(FLG_ACTIVE, &dch->Flags))
216562306a36Sopenharmony_ci			return;
216662306a36Sopenharmony_ci	} else {
216762306a36Sopenharmony_ci		return;
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_cinext_frame:
217062306a36Sopenharmony_ci	/* on first AND before getting next valid frame, R_FIFO must be written
217162306a36Sopenharmony_ci	   to. */
217262306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
217362306a36Sopenharmony_ci	    (hc->chan[ch].protocol == ISDN_P_B_RAW) &&
217462306a36Sopenharmony_ci	    (hc->chan[ch].slot_rx < 0) &&
217562306a36Sopenharmony_ci	    (hc->chan[ch].slot_tx < 0))
217662306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1);
217762306a36Sopenharmony_ci	else
217862306a36Sopenharmony_ci		HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1);
217962306a36Sopenharmony_ci	HFC_wait_nodebug(hc);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	/* ignore if rx is off BUT change fifo (above) to start pending TX */
218262306a36Sopenharmony_ci	if (hc->chan[ch].rx_off) {
218362306a36Sopenharmony_ci		if (bch)
218462306a36Sopenharmony_ci			bch->dropcnt += poll; /* not exact but fair enough */
218562306a36Sopenharmony_ci		return;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
218962306a36Sopenharmony_ci		f1 = HFC_inb_nodebug(hc, A_F1);
219062306a36Sopenharmony_ci		while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) {
219162306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_FIFO)
219262306a36Sopenharmony_ci				printk(KERN_DEBUG
219362306a36Sopenharmony_ci				       "%s(card %d): reread f1 because %d!=%d\n",
219462306a36Sopenharmony_ci				       __func__, hc->id + 1, temp, f1);
219562306a36Sopenharmony_ci			f1 = temp; /* repeat until F1 is equal */
219662306a36Sopenharmony_ci		}
219762306a36Sopenharmony_ci		f2 = HFC_inb_nodebug(hc, A_F2);
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci	z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin;
220062306a36Sopenharmony_ci	while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) {
220162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_FIFO)
220262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s(card %d): reread z2 because "
220362306a36Sopenharmony_ci			       "%d!=%d\n", __func__, hc->id + 1, temp, z2);
220462306a36Sopenharmony_ci		z1 = temp; /* repeat until Z1 is equal */
220562306a36Sopenharmony_ci	}
220662306a36Sopenharmony_ci	z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin;
220762306a36Sopenharmony_ci	Zsize = z1 - z2;
220862306a36Sopenharmony_ci	if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2)
220962306a36Sopenharmony_ci		/* complete hdlc frame */
221062306a36Sopenharmony_ci		Zsize++;
221162306a36Sopenharmony_ci	if (Zsize < 0)
221262306a36Sopenharmony_ci		Zsize += hc->Zlen;
221362306a36Sopenharmony_ci	/* if buffer is empty */
221462306a36Sopenharmony_ci	if (Zsize <= 0)
221562306a36Sopenharmony_ci		return;
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	if (bch) {
221862306a36Sopenharmony_ci		maxlen = bchannel_get_rxbuf(bch, Zsize);
221962306a36Sopenharmony_ci		if (maxlen < 0) {
222062306a36Sopenharmony_ci			pr_warn("card%d.B%d: No bufferspace for %d bytes\n",
222162306a36Sopenharmony_ci				hc->id + 1, bch->nr, Zsize);
222262306a36Sopenharmony_ci			return;
222362306a36Sopenharmony_ci		}
222462306a36Sopenharmony_ci		sp = &bch->rx_skb;
222562306a36Sopenharmony_ci		maxlen = bch->maxlen;
222662306a36Sopenharmony_ci	} else { /* Dchannel */
222762306a36Sopenharmony_ci		sp = &dch->rx_skb;
222862306a36Sopenharmony_ci		maxlen = dch->maxlen + 3;
222962306a36Sopenharmony_ci		if (*sp == NULL) {
223062306a36Sopenharmony_ci			*sp = mI_alloc_skb(maxlen, GFP_ATOMIC);
223162306a36Sopenharmony_ci			if (*sp == NULL) {
223262306a36Sopenharmony_ci				pr_warn("card%d: No mem for dch rx_skb\n",
223362306a36Sopenharmony_ci					hc->id + 1);
223462306a36Sopenharmony_ci				return;
223562306a36Sopenharmony_ci			}
223662306a36Sopenharmony_ci		}
223762306a36Sopenharmony_ci	}
223862306a36Sopenharmony_ci	/* show activity */
223962306a36Sopenharmony_ci	if (dch)
224062306a36Sopenharmony_ci		hc->activity_rx |= 1 << hc->chan[ch].port;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* empty fifo with what we have */
224362306a36Sopenharmony_ci	if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
224462306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_FIFO)
224562306a36Sopenharmony_ci			printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d "
224662306a36Sopenharmony_ci			       "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) "
224762306a36Sopenharmony_ci			       "got=%d (again %d)\n", __func__, hc->id + 1, ch,
224862306a36Sopenharmony_ci			       Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
224962306a36Sopenharmony_ci			       f1, f2, Zsize + (*sp)->len, again);
225062306a36Sopenharmony_ci		/* HDLC */
225162306a36Sopenharmony_ci		if ((Zsize + (*sp)->len) > maxlen) {
225262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_FIFO)
225362306a36Sopenharmony_ci				printk(KERN_DEBUG
225462306a36Sopenharmony_ci				       "%s(card %d): hdlc-frame too large.\n",
225562306a36Sopenharmony_ci				       __func__, hc->id + 1);
225662306a36Sopenharmony_ci			skb_trim(*sp, 0);
225762306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
225862306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
225962306a36Sopenharmony_ci			return;
226062306a36Sopenharmony_ci		}
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci		hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci		if (f1 != f2) {
226562306a36Sopenharmony_ci			/* increment Z2,F2-counter */
226662306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
226762306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
226862306a36Sopenharmony_ci			/* check size */
226962306a36Sopenharmony_ci			if ((*sp)->len < 4) {
227062306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_FIFO)
227162306a36Sopenharmony_ci					printk(KERN_DEBUG
227262306a36Sopenharmony_ci					       "%s(card %d): Frame below minimum "
227362306a36Sopenharmony_ci					       "size\n", __func__, hc->id + 1);
227462306a36Sopenharmony_ci				skb_trim(*sp, 0);
227562306a36Sopenharmony_ci				goto next_frame;
227662306a36Sopenharmony_ci			}
227762306a36Sopenharmony_ci			/* there is at least one complete frame, check crc */
227862306a36Sopenharmony_ci			if ((*sp)->data[(*sp)->len - 1]) {
227962306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_CRC)
228062306a36Sopenharmony_ci					printk(KERN_DEBUG
228162306a36Sopenharmony_ci					       "%s: CRC-error\n", __func__);
228262306a36Sopenharmony_ci				skb_trim(*sp, 0);
228362306a36Sopenharmony_ci				goto next_frame;
228462306a36Sopenharmony_ci			}
228562306a36Sopenharmony_ci			skb_trim(*sp, (*sp)->len - 3);
228662306a36Sopenharmony_ci			if ((*sp)->len < MISDN_COPY_SIZE) {
228762306a36Sopenharmony_ci				skb = *sp;
228862306a36Sopenharmony_ci				*sp = mI_alloc_skb(skb->len, GFP_ATOMIC);
228962306a36Sopenharmony_ci				if (*sp) {
229062306a36Sopenharmony_ci					skb_put_data(*sp, skb->data, skb->len);
229162306a36Sopenharmony_ci					skb_trim(skb, 0);
229262306a36Sopenharmony_ci				} else {
229362306a36Sopenharmony_ci					printk(KERN_DEBUG "%s: No mem\n",
229462306a36Sopenharmony_ci					       __func__);
229562306a36Sopenharmony_ci					*sp = skb;
229662306a36Sopenharmony_ci					skb = NULL;
229762306a36Sopenharmony_ci				}
229862306a36Sopenharmony_ci			} else {
229962306a36Sopenharmony_ci				skb = NULL;
230062306a36Sopenharmony_ci			}
230162306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_FIFO) {
230262306a36Sopenharmony_ci				printk(KERN_DEBUG "%s(card %d):",
230362306a36Sopenharmony_ci				       __func__, hc->id + 1);
230462306a36Sopenharmony_ci				temp = 0;
230562306a36Sopenharmony_ci				while (temp < (*sp)->len)
230662306a36Sopenharmony_ci					printk(" %02x", (*sp)->data[temp++]);
230762306a36Sopenharmony_ci				printk("\n");
230862306a36Sopenharmony_ci			}
230962306a36Sopenharmony_ci			if (dch)
231062306a36Sopenharmony_ci				recv_Dchannel(dch);
231162306a36Sopenharmony_ci			else
231262306a36Sopenharmony_ci				recv_Bchannel(bch, MISDN_ID_ANY, false);
231362306a36Sopenharmony_ci			*sp = skb;
231462306a36Sopenharmony_ci			again++;
231562306a36Sopenharmony_ci			goto next_frame;
231662306a36Sopenharmony_ci		}
231762306a36Sopenharmony_ci		/* there is an incomplete frame */
231862306a36Sopenharmony_ci	} else {
231962306a36Sopenharmony_ci		/* transparent */
232062306a36Sopenharmony_ci		hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
232162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_FIFO)
232262306a36Sopenharmony_ci			printk(KERN_DEBUG
232362306a36Sopenharmony_ci			       "%s(card %d): fifo(%d) reading %d bytes "
232462306a36Sopenharmony_ci			       "(z1=%04x, z2=%04x) TRANS\n",
232562306a36Sopenharmony_ci			       __func__, hc->id + 1, ch, Zsize, z1, z2);
232662306a36Sopenharmony_ci		/* only bch is transparent */
232762306a36Sopenharmony_ci		recv_Bchannel(bch, hc->chan[ch].Zfill, false);
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci}
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci/*
233362306a36Sopenharmony_ci * Interrupt handler
233462306a36Sopenharmony_ci */
233562306a36Sopenharmony_cistatic void
233662306a36Sopenharmony_cisignal_state_up(struct dchannel *dch, int info, char *msg)
233762306a36Sopenharmony_ci{
233862306a36Sopenharmony_ci	struct sk_buff	*skb;
233962306a36Sopenharmony_ci	int		id, data = info;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_STATE)
234262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: %s\n", __func__, msg);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	id = TEI_SAPI | (GROUP_TEI << 8); /* manager address */
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	skb = _alloc_mISDN_skb(MPH_INFORMATION_IND, id, sizeof(data), &data,
234762306a36Sopenharmony_ci			       GFP_ATOMIC);
234862306a36Sopenharmony_ci	if (!skb)
234962306a36Sopenharmony_ci		return;
235062306a36Sopenharmony_ci	recv_Dchannel_skb(dch, skb);
235162306a36Sopenharmony_ci}
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cistatic inline void
235462306a36Sopenharmony_cihandle_timer_irq(struct hfc_multi *hc)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	int		ch, temp;
235762306a36Sopenharmony_ci	struct dchannel	*dch;
235862306a36Sopenharmony_ci	u_long		flags;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	/* process queued resync jobs */
236162306a36Sopenharmony_ci	if (hc->e1_resync) {
236262306a36Sopenharmony_ci		/* lock, so e1_resync gets not changed */
236362306a36Sopenharmony_ci		spin_lock_irqsave(&HFClock, flags);
236462306a36Sopenharmony_ci		if (hc->e1_resync & 1) {
236562306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
236662306a36Sopenharmony_ci				printk(KERN_DEBUG "Enable SYNC_I\n");
236762306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC);
236862306a36Sopenharmony_ci			/* disable JATT, if RX_SYNC is set */
236962306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
237062306a36Sopenharmony_ci				HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
237162306a36Sopenharmony_ci		}
237262306a36Sopenharmony_ci		if (hc->e1_resync & 2) {
237362306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
237462306a36Sopenharmony_ci				printk(KERN_DEBUG "Enable jatt PLL\n");
237562306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
237662306a36Sopenharmony_ci		}
237762306a36Sopenharmony_ci		if (hc->e1_resync & 4) {
237862306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_PLXSD)
237962306a36Sopenharmony_ci				printk(KERN_DEBUG
238062306a36Sopenharmony_ci				       "Enable QUARTZ for HFC-E1\n");
238162306a36Sopenharmony_ci			/* set jatt to quartz */
238262306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC
238362306a36Sopenharmony_ci				 | V_JATT_OFF);
238462306a36Sopenharmony_ci			/* switch to JATT, in case it is not already */
238562306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_OUT, 0);
238662306a36Sopenharmony_ci		}
238762306a36Sopenharmony_ci		hc->e1_resync = 0;
238862306a36Sopenharmony_ci		spin_unlock_irqrestore(&HFClock, flags);
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1)
239262306a36Sopenharmony_ci		for (ch = 0; ch <= 31; ch++) {
239362306a36Sopenharmony_ci			if (hc->created[hc->chan[ch].port]) {
239462306a36Sopenharmony_ci				hfcmulti_tx(hc, ch);
239562306a36Sopenharmony_ci				/* fifo is started when switching to rx-fifo */
239662306a36Sopenharmony_ci				hfcmulti_rx(hc, ch);
239762306a36Sopenharmony_ci				if (hc->chan[ch].dch &&
239862306a36Sopenharmony_ci				    hc->chan[ch].nt_timer > -1) {
239962306a36Sopenharmony_ci					dch = hc->chan[ch].dch;
240062306a36Sopenharmony_ci					if (!(--hc->chan[ch].nt_timer)) {
240162306a36Sopenharmony_ci						schedule_event(dch,
240262306a36Sopenharmony_ci							       FLG_PHCHANGE);
240362306a36Sopenharmony_ci						if (debug &
240462306a36Sopenharmony_ci						    DEBUG_HFCMULTI_STATE)
240562306a36Sopenharmony_ci							printk(KERN_DEBUG
240662306a36Sopenharmony_ci							       "%s: nt_timer at "
240762306a36Sopenharmony_ci							       "state %x\n",
240862306a36Sopenharmony_ci							       __func__,
240962306a36Sopenharmony_ci							       dch->state);
241062306a36Sopenharmony_ci					}
241162306a36Sopenharmony_ci				}
241262306a36Sopenharmony_ci			}
241362306a36Sopenharmony_ci		}
241462306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
241562306a36Sopenharmony_ci		dch = hc->chan[hc->dnum[0]].dch;
241662306a36Sopenharmony_ci		/* LOS */
241762306a36Sopenharmony_ci		temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS;
241862306a36Sopenharmony_ci		hc->chan[hc->dnum[0]].los = temp;
241962306a36Sopenharmony_ci		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
242062306a36Sopenharmony_ci			if (!temp && hc->chan[hc->dnum[0]].los)
242162306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_LOS_ON,
242262306a36Sopenharmony_ci						"LOS detected");
242362306a36Sopenharmony_ci			if (temp && !hc->chan[hc->dnum[0]].los)
242462306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_LOS_OFF,
242562306a36Sopenharmony_ci						"LOS gone");
242662306a36Sopenharmony_ci		}
242762306a36Sopenharmony_ci		if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) {
242862306a36Sopenharmony_ci			/* AIS */
242962306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS;
243062306a36Sopenharmony_ci			if (!temp && hc->chan[hc->dnum[0]].ais)
243162306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_AIS_ON,
243262306a36Sopenharmony_ci						"AIS detected");
243362306a36Sopenharmony_ci			if (temp && !hc->chan[hc->dnum[0]].ais)
243462306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_AIS_OFF,
243562306a36Sopenharmony_ci						"AIS gone");
243662306a36Sopenharmony_ci			hc->chan[hc->dnum[0]].ais = temp;
243762306a36Sopenharmony_ci		}
243862306a36Sopenharmony_ci		if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) {
243962306a36Sopenharmony_ci			/* SLIP */
244062306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX;
244162306a36Sopenharmony_ci			if (!temp && hc->chan[hc->dnum[0]].slip_rx)
244262306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_SLIP_RX,
244362306a36Sopenharmony_ci						" bit SLIP detected RX");
244462306a36Sopenharmony_ci			hc->chan[hc->dnum[0]].slip_rx = temp;
244562306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX;
244662306a36Sopenharmony_ci			if (!temp && hc->chan[hc->dnum[0]].slip_tx)
244762306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_SLIP_TX,
244862306a36Sopenharmony_ci						" bit SLIP detected TX");
244962306a36Sopenharmony_ci			hc->chan[hc->dnum[0]].slip_tx = temp;
245062306a36Sopenharmony_ci		}
245162306a36Sopenharmony_ci		if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) {
245262306a36Sopenharmony_ci			/* RDI */
245362306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A;
245462306a36Sopenharmony_ci			if (!temp && hc->chan[hc->dnum[0]].rdi)
245562306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_RDI_ON,
245662306a36Sopenharmony_ci						"RDI detected");
245762306a36Sopenharmony_ci			if (temp && !hc->chan[hc->dnum[0]].rdi)
245862306a36Sopenharmony_ci				signal_state_up(dch, L1_SIGNAL_RDI_OFF,
245962306a36Sopenharmony_ci						"RDI gone");
246062306a36Sopenharmony_ci			hc->chan[hc->dnum[0]].rdi = temp;
246162306a36Sopenharmony_ci		}
246262306a36Sopenharmony_ci		temp = HFC_inb_nodebug(hc, R_JATT_DIR);
246362306a36Sopenharmony_ci		switch (hc->chan[hc->dnum[0]].sync) {
246462306a36Sopenharmony_ci		case 0:
246562306a36Sopenharmony_ci			if ((temp & 0x60) == 0x60) {
246662306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_SYNC)
246762306a36Sopenharmony_ci					printk(KERN_DEBUG
246862306a36Sopenharmony_ci					       "%s: (id=%d) E1 now "
246962306a36Sopenharmony_ci					       "in clock sync\n",
247062306a36Sopenharmony_ci					       __func__, hc->id);
247162306a36Sopenharmony_ci				HFC_outb(hc, R_RX_OFF,
247262306a36Sopenharmony_ci				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
247362306a36Sopenharmony_ci				HFC_outb(hc, R_TX_OFF,
247462306a36Sopenharmony_ci				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
247562306a36Sopenharmony_ci				hc->chan[hc->dnum[0]].sync = 1;
247662306a36Sopenharmony_ci				goto check_framesync;
247762306a36Sopenharmony_ci			}
247862306a36Sopenharmony_ci			break;
247962306a36Sopenharmony_ci		case 1:
248062306a36Sopenharmony_ci			if ((temp & 0x60) != 0x60) {
248162306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_SYNC)
248262306a36Sopenharmony_ci					printk(KERN_DEBUG
248362306a36Sopenharmony_ci					       "%s: (id=%d) E1 "
248462306a36Sopenharmony_ci					       "lost clock sync\n",
248562306a36Sopenharmony_ci					       __func__, hc->id);
248662306a36Sopenharmony_ci				hc->chan[hc->dnum[0]].sync = 0;
248762306a36Sopenharmony_ci				break;
248862306a36Sopenharmony_ci			}
248962306a36Sopenharmony_ci		check_framesync:
249062306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_SYNC_STA);
249162306a36Sopenharmony_ci			if (temp == 0x27) {
249262306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_SYNC)
249362306a36Sopenharmony_ci					printk(KERN_DEBUG
249462306a36Sopenharmony_ci					       "%s: (id=%d) E1 "
249562306a36Sopenharmony_ci					       "now in frame sync\n",
249662306a36Sopenharmony_ci					       __func__, hc->id);
249762306a36Sopenharmony_ci				hc->chan[hc->dnum[0]].sync = 2;
249862306a36Sopenharmony_ci			}
249962306a36Sopenharmony_ci			break;
250062306a36Sopenharmony_ci		case 2:
250162306a36Sopenharmony_ci			if ((temp & 0x60) != 0x60) {
250262306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_SYNC)
250362306a36Sopenharmony_ci					printk(KERN_DEBUG
250462306a36Sopenharmony_ci					       "%s: (id=%d) E1 lost "
250562306a36Sopenharmony_ci					       "clock & frame sync\n",
250662306a36Sopenharmony_ci					       __func__, hc->id);
250762306a36Sopenharmony_ci				hc->chan[hc->dnum[0]].sync = 0;
250862306a36Sopenharmony_ci				break;
250962306a36Sopenharmony_ci			}
251062306a36Sopenharmony_ci			temp = HFC_inb_nodebug(hc, R_SYNC_STA);
251162306a36Sopenharmony_ci			if (temp != 0x27) {
251262306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_SYNC)
251362306a36Sopenharmony_ci					printk(KERN_DEBUG
251462306a36Sopenharmony_ci					       "%s: (id=%d) E1 "
251562306a36Sopenharmony_ci					       "lost frame sync\n",
251662306a36Sopenharmony_ci					       __func__, hc->id);
251762306a36Sopenharmony_ci				hc->chan[hc->dnum[0]].sync = 1;
251862306a36Sopenharmony_ci			}
251962306a36Sopenharmony_ci			break;
252062306a36Sopenharmony_ci		}
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip))
252462306a36Sopenharmony_ci		hfcmulti_watchdog(hc);
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	if (hc->leds)
252762306a36Sopenharmony_ci		hfcmulti_leds(hc);
252862306a36Sopenharmony_ci}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_cistatic void
253162306a36Sopenharmony_ciph_state_irq(struct hfc_multi *hc, u_char r_irq_statech)
253262306a36Sopenharmony_ci{
253362306a36Sopenharmony_ci	struct dchannel	*dch;
253462306a36Sopenharmony_ci	int		ch;
253562306a36Sopenharmony_ci	int		active;
253662306a36Sopenharmony_ci	u_char		st_status, temp;
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	/* state machine */
253962306a36Sopenharmony_ci	for (ch = 0; ch <= 31; ch++) {
254062306a36Sopenharmony_ci		if (hc->chan[ch].dch) {
254162306a36Sopenharmony_ci			dch = hc->chan[ch].dch;
254262306a36Sopenharmony_ci			if (r_irq_statech & 1) {
254362306a36Sopenharmony_ci				HFC_outb_nodebug(hc, R_ST_SEL,
254462306a36Sopenharmony_ci						 hc->chan[ch].port);
254562306a36Sopenharmony_ci				/* undocumented: delay after R_ST_SEL */
254662306a36Sopenharmony_ci				udelay(1);
254762306a36Sopenharmony_ci				/* undocumented: status changes during read */
254862306a36Sopenharmony_ci				st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE);
254962306a36Sopenharmony_ci				while (st_status != (temp =
255062306a36Sopenharmony_ci						     HFC_inb_nodebug(hc, A_ST_RD_STATE))) {
255162306a36Sopenharmony_ci					if (debug & DEBUG_HFCMULTI_STATE)
255262306a36Sopenharmony_ci						printk(KERN_DEBUG "%s: reread "
255362306a36Sopenharmony_ci						       "STATE because %d!=%d\n",
255462306a36Sopenharmony_ci						       __func__, temp,
255562306a36Sopenharmony_ci						       st_status);
255662306a36Sopenharmony_ci					st_status = temp; /* repeat */
255762306a36Sopenharmony_ci				}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci				/* Speech Design TE-sync indication */
256062306a36Sopenharmony_ci				if (test_bit(HFC_CHIP_PLXSD, &hc->chip) &&
256162306a36Sopenharmony_ci				    dch->dev.D.protocol == ISDN_P_TE_S0) {
256262306a36Sopenharmony_ci					if (st_status & V_FR_SYNC_ST)
256362306a36Sopenharmony_ci						hc->syncronized |=
256462306a36Sopenharmony_ci							(1 << hc->chan[ch].port);
256562306a36Sopenharmony_ci					else
256662306a36Sopenharmony_ci						hc->syncronized &=
256762306a36Sopenharmony_ci							~(1 << hc->chan[ch].port);
256862306a36Sopenharmony_ci				}
256962306a36Sopenharmony_ci				dch->state = st_status & 0x0f;
257062306a36Sopenharmony_ci				if (dch->dev.D.protocol == ISDN_P_NT_S0)
257162306a36Sopenharmony_ci					active = 3;
257262306a36Sopenharmony_ci				else
257362306a36Sopenharmony_ci					active = 7;
257462306a36Sopenharmony_ci				if (dch->state == active) {
257562306a36Sopenharmony_ci					HFC_outb_nodebug(hc, R_FIFO,
257662306a36Sopenharmony_ci							 (ch << 1) | 1);
257762306a36Sopenharmony_ci					HFC_wait_nodebug(hc);
257862306a36Sopenharmony_ci					HFC_outb_nodebug(hc,
257962306a36Sopenharmony_ci							 R_INC_RES_FIFO, V_RES_F);
258062306a36Sopenharmony_ci					HFC_wait_nodebug(hc);
258162306a36Sopenharmony_ci					dch->tx_idx = 0;
258262306a36Sopenharmony_ci				}
258362306a36Sopenharmony_ci				schedule_event(dch, FLG_PHCHANGE);
258462306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_STATE)
258562306a36Sopenharmony_ci					printk(KERN_DEBUG
258662306a36Sopenharmony_ci					       "%s: S/T newstate %x port %d\n",
258762306a36Sopenharmony_ci					       __func__, dch->state,
258862306a36Sopenharmony_ci					       hc->chan[ch].port);
258962306a36Sopenharmony_ci			}
259062306a36Sopenharmony_ci			r_irq_statech >>= 1;
259162306a36Sopenharmony_ci		}
259262306a36Sopenharmony_ci	}
259362306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
259462306a36Sopenharmony_ci		plxsd_checksync(hc, 0);
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_cistatic void
259862306a36Sopenharmony_cififo_irq(struct hfc_multi *hc, int block)
259962306a36Sopenharmony_ci{
260062306a36Sopenharmony_ci	int	ch, j;
260162306a36Sopenharmony_ci	struct dchannel	*dch;
260262306a36Sopenharmony_ci	struct bchannel	*bch;
260362306a36Sopenharmony_ci	u_char r_irq_fifo_bl;
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	r_irq_fifo_bl = HFC_inb_nodebug(hc, R_IRQ_FIFO_BL0 + block);
260662306a36Sopenharmony_ci	j = 0;
260762306a36Sopenharmony_ci	while (j < 8) {
260862306a36Sopenharmony_ci		ch = (block << 2) + (j >> 1);
260962306a36Sopenharmony_ci		dch = hc->chan[ch].dch;
261062306a36Sopenharmony_ci		bch = hc->chan[ch].bch;
261162306a36Sopenharmony_ci		if (((!dch) && (!bch)) || (!hc->created[hc->chan[ch].port])) {
261262306a36Sopenharmony_ci			j += 2;
261362306a36Sopenharmony_ci			continue;
261462306a36Sopenharmony_ci		}
261562306a36Sopenharmony_ci		if (dch && (r_irq_fifo_bl & (1 << j)) &&
261662306a36Sopenharmony_ci		    test_bit(FLG_ACTIVE, &dch->Flags)) {
261762306a36Sopenharmony_ci			hfcmulti_tx(hc, ch);
261862306a36Sopenharmony_ci			/* start fifo */
261962306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_FIFO, 0);
262062306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
262162306a36Sopenharmony_ci		}
262262306a36Sopenharmony_ci		if (bch && (r_irq_fifo_bl & (1 << j)) &&
262362306a36Sopenharmony_ci		    test_bit(FLG_ACTIVE, &bch->Flags)) {
262462306a36Sopenharmony_ci			hfcmulti_tx(hc, ch);
262562306a36Sopenharmony_ci			/* start fifo */
262662306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_FIFO, 0);
262762306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
262862306a36Sopenharmony_ci		}
262962306a36Sopenharmony_ci		j++;
263062306a36Sopenharmony_ci		if (dch && (r_irq_fifo_bl & (1 << j)) &&
263162306a36Sopenharmony_ci		    test_bit(FLG_ACTIVE, &dch->Flags)) {
263262306a36Sopenharmony_ci			hfcmulti_rx(hc, ch);
263362306a36Sopenharmony_ci		}
263462306a36Sopenharmony_ci		if (bch && (r_irq_fifo_bl & (1 << j)) &&
263562306a36Sopenharmony_ci		    test_bit(FLG_ACTIVE, &bch->Flags)) {
263662306a36Sopenharmony_ci			hfcmulti_rx(hc, ch);
263762306a36Sopenharmony_ci		}
263862306a36Sopenharmony_ci		j++;
263962306a36Sopenharmony_ci	}
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci#ifdef IRQ_DEBUG
264362306a36Sopenharmony_ciint irqsem;
264462306a36Sopenharmony_ci#endif
264562306a36Sopenharmony_cistatic irqreturn_t
264662306a36Sopenharmony_cihfcmulti_interrupt(int intno, void *dev_id)
264762306a36Sopenharmony_ci{
264862306a36Sopenharmony_ci#ifdef IRQCOUNT_DEBUG
264962306a36Sopenharmony_ci	static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0,
265062306a36Sopenharmony_ci		iq5 = 0, iq6 = 0, iqcnt = 0;
265162306a36Sopenharmony_ci#endif
265262306a36Sopenharmony_ci	struct hfc_multi	*hc = dev_id;
265362306a36Sopenharmony_ci	struct dchannel		*dch;
265462306a36Sopenharmony_ci	u_char			r_irq_statech, status, r_irq_misc, r_irq_oview;
265562306a36Sopenharmony_ci	int			i;
265662306a36Sopenharmony_ci	void __iomem		*plx_acc;
265762306a36Sopenharmony_ci	u_short			wval;
265862306a36Sopenharmony_ci	u_char			e1_syncsta, temp, temp2;
265962306a36Sopenharmony_ci	u_long			flags;
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	if (!hc) {
266262306a36Sopenharmony_ci		printk(KERN_ERR "HFC-multi: Spurious interrupt!\n");
266362306a36Sopenharmony_ci		return IRQ_NONE;
266462306a36Sopenharmony_ci	}
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci	spin_lock(&hc->lock);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci#ifdef IRQ_DEBUG
266962306a36Sopenharmony_ci	if (irqsem)
267062306a36Sopenharmony_ci		printk(KERN_ERR "irq for card %d during irq from "
267162306a36Sopenharmony_ci		       "card %d, this is no bug.\n", hc->id + 1, irqsem);
267262306a36Sopenharmony_ci	irqsem = hc->id + 1;
267362306a36Sopenharmony_ci#endif
267462306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx
267562306a36Sopenharmony_ci	if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk)
267662306a36Sopenharmony_ci		goto irq_notforus;
267762306a36Sopenharmony_ci#endif
267862306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
267962306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, flags);
268062306a36Sopenharmony_ci		plx_acc = hc->plx_membase + PLX_INTCSR;
268162306a36Sopenharmony_ci		wval = readw(plx_acc);
268262306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, flags);
268362306a36Sopenharmony_ci		if (!(wval & PLX_INTCSR_LINTI1_STATUS))
268462306a36Sopenharmony_ci			goto irq_notforus;
268562306a36Sopenharmony_ci	}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	status = HFC_inb_nodebug(hc, R_STATUS);
268862306a36Sopenharmony_ci	r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH);
268962306a36Sopenharmony_ci#ifdef IRQCOUNT_DEBUG
269062306a36Sopenharmony_ci	if (r_irq_statech)
269162306a36Sopenharmony_ci		iq1++;
269262306a36Sopenharmony_ci	if (status & V_DTMF_STA)
269362306a36Sopenharmony_ci		iq2++;
269462306a36Sopenharmony_ci	if (status & V_LOST_STA)
269562306a36Sopenharmony_ci		iq3++;
269662306a36Sopenharmony_ci	if (status & V_EXT_IRQSTA)
269762306a36Sopenharmony_ci		iq4++;
269862306a36Sopenharmony_ci	if (status & V_MISC_IRQSTA)
269962306a36Sopenharmony_ci		iq5++;
270062306a36Sopenharmony_ci	if (status & V_FR_IRQSTA)
270162306a36Sopenharmony_ci		iq6++;
270262306a36Sopenharmony_ci	if (iqcnt++ > 5000) {
270362306a36Sopenharmony_ci		printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n",
270462306a36Sopenharmony_ci		       iq1, iq2, iq3, iq4, iq5, iq6);
270562306a36Sopenharmony_ci		iqcnt = 0;
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci#endif
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci	if (!r_irq_statech &&
271062306a36Sopenharmony_ci	    !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA |
271162306a36Sopenharmony_ci			V_MISC_IRQSTA | V_FR_IRQSTA))) {
271262306a36Sopenharmony_ci		/* irq is not for us */
271362306a36Sopenharmony_ci		goto irq_notforus;
271462306a36Sopenharmony_ci	}
271562306a36Sopenharmony_ci	hc->irqcnt++;
271662306a36Sopenharmony_ci	if (r_irq_statech) {
271762306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_E1)
271862306a36Sopenharmony_ci			ph_state_irq(hc, r_irq_statech);
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci	if (status & V_LOST_STA) {
272162306a36Sopenharmony_ci		/* LOST IRQ */
272262306a36Sopenharmony_ci		HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */
272362306a36Sopenharmony_ci	}
272462306a36Sopenharmony_ci	if (status & V_MISC_IRQSTA) {
272562306a36Sopenharmony_ci		/* misc IRQ */
272662306a36Sopenharmony_ci		r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC);
272762306a36Sopenharmony_ci		r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */
272862306a36Sopenharmony_ci		if (r_irq_misc & V_STA_IRQ) {
272962306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_E1) {
273062306a36Sopenharmony_ci				/* state machine */
273162306a36Sopenharmony_ci				dch = hc->chan[hc->dnum[0]].dch;
273262306a36Sopenharmony_ci				e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
273362306a36Sopenharmony_ci				if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
273462306a36Sopenharmony_ci				    && hc->e1_getclock) {
273562306a36Sopenharmony_ci					if (e1_syncsta & V_FR_SYNC_E1)
273662306a36Sopenharmony_ci						hc->syncronized = 1;
273762306a36Sopenharmony_ci					else
273862306a36Sopenharmony_ci						hc->syncronized = 0;
273962306a36Sopenharmony_ci				}
274062306a36Sopenharmony_ci				/* undocumented: status changes during read */
274162306a36Sopenharmony_ci				temp = HFC_inb_nodebug(hc, R_E1_RD_STA);
274262306a36Sopenharmony_ci				while (temp != (temp2 =
274362306a36Sopenharmony_ci						      HFC_inb_nodebug(hc, R_E1_RD_STA))) {
274462306a36Sopenharmony_ci					if (debug & DEBUG_HFCMULTI_STATE)
274562306a36Sopenharmony_ci						printk(KERN_DEBUG "%s: reread "
274662306a36Sopenharmony_ci						       "STATE because %d!=%d\n",
274762306a36Sopenharmony_ci						    __func__, temp, temp2);
274862306a36Sopenharmony_ci					temp = temp2; /* repeat */
274962306a36Sopenharmony_ci				}
275062306a36Sopenharmony_ci				/* broadcast state change to all fragments */
275162306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_STATE)
275262306a36Sopenharmony_ci					printk(KERN_DEBUG
275362306a36Sopenharmony_ci					       "%s: E1 (id=%d) newstate %x\n",
275462306a36Sopenharmony_ci					    __func__, hc->id, temp & 0x7);
275562306a36Sopenharmony_ci				for (i = 0; i < hc->ports; i++) {
275662306a36Sopenharmony_ci					dch = hc->chan[hc->dnum[i]].dch;
275762306a36Sopenharmony_ci					dch->state = temp & 0x7;
275862306a36Sopenharmony_ci					schedule_event(dch, FLG_PHCHANGE);
275962306a36Sopenharmony_ci				}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci				if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
276262306a36Sopenharmony_ci					plxsd_checksync(hc, 0);
276362306a36Sopenharmony_ci			}
276462306a36Sopenharmony_ci		}
276562306a36Sopenharmony_ci		if (r_irq_misc & V_TI_IRQ) {
276662306a36Sopenharmony_ci			if (hc->iclock_on)
276762306a36Sopenharmony_ci				mISDN_clock_update(hc->iclock, poll, NULL);
276862306a36Sopenharmony_ci			handle_timer_irq(hc);
276962306a36Sopenharmony_ci		}
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci		if (r_irq_misc & V_DTMF_IRQ)
277262306a36Sopenharmony_ci			hfcmulti_dtmf(hc);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci		if (r_irq_misc & V_IRQ_PROC) {
277562306a36Sopenharmony_ci			static int irq_proc_cnt;
277662306a36Sopenharmony_ci			if (!irq_proc_cnt++)
277762306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: got V_IRQ_PROC -"
277862306a36Sopenharmony_ci				       " this should not happen\n", __func__);
277962306a36Sopenharmony_ci		}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci	if (status & V_FR_IRQSTA) {
278362306a36Sopenharmony_ci		/* FIFO IRQ */
278462306a36Sopenharmony_ci		r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW);
278562306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
278662306a36Sopenharmony_ci			if (r_irq_oview & (1 << i))
278762306a36Sopenharmony_ci				fifo_irq(hc, i);
278862306a36Sopenharmony_ci		}
278962306a36Sopenharmony_ci	}
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci#ifdef IRQ_DEBUG
279262306a36Sopenharmony_ci	irqsem = 0;
279362306a36Sopenharmony_ci#endif
279462306a36Sopenharmony_ci	spin_unlock(&hc->lock);
279562306a36Sopenharmony_ci	return IRQ_HANDLED;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ciirq_notforus:
279862306a36Sopenharmony_ci#ifdef IRQ_DEBUG
279962306a36Sopenharmony_ci	irqsem = 0;
280062306a36Sopenharmony_ci#endif
280162306a36Sopenharmony_ci	spin_unlock(&hc->lock);
280262306a36Sopenharmony_ci	return IRQ_NONE;
280362306a36Sopenharmony_ci}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci/*
280762306a36Sopenharmony_ci * timer callback for D-chan busy resolution. Currently no function
280862306a36Sopenharmony_ci */
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_cistatic void
281162306a36Sopenharmony_cihfcmulti_dbusy_timer(struct timer_list *t)
281262306a36Sopenharmony_ci{
281362306a36Sopenharmony_ci}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci/*
281762306a36Sopenharmony_ci * activate/deactivate hardware for selected channels and mode
281862306a36Sopenharmony_ci *
281962306a36Sopenharmony_ci * configure B-channel with the given protocol
282062306a36Sopenharmony_ci * ch eqals to the HFC-channel (0-31)
282162306a36Sopenharmony_ci * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31
282262306a36Sopenharmony_ci * for S/T, 1-31 for E1)
282362306a36Sopenharmony_ci * the hdlc interrupts will be set/unset
282462306a36Sopenharmony_ci */
282562306a36Sopenharmony_cistatic int
282662306a36Sopenharmony_cimode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
282762306a36Sopenharmony_ci	      int bank_tx, int slot_rx, int bank_rx)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci	int flow_tx = 0, flow_rx = 0, routing = 0;
283062306a36Sopenharmony_ci	int oslot_tx, oslot_rx;
283162306a36Sopenharmony_ci	int conf;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	if (ch < 0 || ch > 31)
283462306a36Sopenharmony_ci		return -EINVAL;
283562306a36Sopenharmony_ci	oslot_tx = hc->chan[ch].slot_tx;
283662306a36Sopenharmony_ci	oslot_rx = hc->chan[ch].slot_rx;
283762306a36Sopenharmony_ci	conf = hc->chan[ch].conf;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_MODE)
284062306a36Sopenharmony_ci		printk(KERN_DEBUG
284162306a36Sopenharmony_ci		       "%s: card %d channel %d protocol %x slot old=%d new=%d "
284262306a36Sopenharmony_ci		       "bank new=%d (TX) slot old=%d new=%d bank new=%d (RX)\n",
284362306a36Sopenharmony_ci		       __func__, hc->id, ch, protocol, oslot_tx, slot_tx,
284462306a36Sopenharmony_ci		       bank_tx, oslot_rx, slot_rx, bank_rx);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	if (oslot_tx >= 0 && slot_tx != oslot_tx) {
284762306a36Sopenharmony_ci		/* remove from slot */
284862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
284962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: remove from slot %d (TX)\n",
285062306a36Sopenharmony_ci			       __func__, oslot_tx);
285162306a36Sopenharmony_ci		if (hc->slot_owner[oslot_tx << 1] == ch) {
285262306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, oslot_tx << 1);
285362306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0);
285462306a36Sopenharmony_ci			if (hc->ctype != HFC_TYPE_XHFC)
285562306a36Sopenharmony_ci				HFC_outb(hc, A_CONF, 0);
285662306a36Sopenharmony_ci			hc->slot_owner[oslot_tx << 1] = -1;
285762306a36Sopenharmony_ci		} else {
285862306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MODE)
285962306a36Sopenharmony_ci				printk(KERN_DEBUG
286062306a36Sopenharmony_ci				       "%s: we are not owner of this tx slot "
286162306a36Sopenharmony_ci				       "anymore, channel %d is.\n",
286262306a36Sopenharmony_ci				       __func__, hc->slot_owner[oslot_tx << 1]);
286362306a36Sopenharmony_ci		}
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	if (oslot_rx >= 0 && slot_rx != oslot_rx) {
286762306a36Sopenharmony_ci		/* remove from slot */
286862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
286962306a36Sopenharmony_ci			printk(KERN_DEBUG
287062306a36Sopenharmony_ci			       "%s: remove from slot %d (RX)\n",
287162306a36Sopenharmony_ci			       __func__, oslot_rx);
287262306a36Sopenharmony_ci		if (hc->slot_owner[(oslot_rx << 1) | 1] == ch) {
287362306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, (oslot_rx << 1) | V_SL_DIR);
287462306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0);
287562306a36Sopenharmony_ci			hc->slot_owner[(oslot_rx << 1) | 1] = -1;
287662306a36Sopenharmony_ci		} else {
287762306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MODE)
287862306a36Sopenharmony_ci				printk(KERN_DEBUG
287962306a36Sopenharmony_ci				       "%s: we are not owner of this rx slot "
288062306a36Sopenharmony_ci				       "anymore, channel %d is.\n",
288162306a36Sopenharmony_ci				       __func__,
288262306a36Sopenharmony_ci				       hc->slot_owner[(oslot_rx << 1) | 1]);
288362306a36Sopenharmony_ci		}
288462306a36Sopenharmony_ci	}
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	if (slot_tx < 0) {
288762306a36Sopenharmony_ci		flow_tx = 0x80; /* FIFO->ST */
288862306a36Sopenharmony_ci		/* disable pcm slot */
288962306a36Sopenharmony_ci		hc->chan[ch].slot_tx = -1;
289062306a36Sopenharmony_ci		hc->chan[ch].bank_tx = 0;
289162306a36Sopenharmony_ci	} else {
289262306a36Sopenharmony_ci		/* set pcm slot */
289362306a36Sopenharmony_ci		if (hc->chan[ch].txpending)
289462306a36Sopenharmony_ci			flow_tx = 0x80; /* FIFO->ST */
289562306a36Sopenharmony_ci		else
289662306a36Sopenharmony_ci			flow_tx = 0xc0; /* PCM->ST */
289762306a36Sopenharmony_ci		/* put on slot */
289862306a36Sopenharmony_ci		routing = bank_tx ? 0xc0 : 0x80;
289962306a36Sopenharmony_ci		if (conf >= 0 || bank_tx > 1)
290062306a36Sopenharmony_ci			routing = 0x40; /* loop */
290162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
290262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: put channel %d to slot %d bank"
290362306a36Sopenharmony_ci			       " %d flow %02x routing %02x conf %d (TX)\n",
290462306a36Sopenharmony_ci			       __func__, ch, slot_tx, bank_tx,
290562306a36Sopenharmony_ci			       flow_tx, routing, conf);
290662306a36Sopenharmony_ci		HFC_outb(hc, R_SLOT, slot_tx << 1);
290762306a36Sopenharmony_ci		HFC_outb(hc, A_SL_CFG, (ch << 1) | routing);
290862306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_XHFC)
290962306a36Sopenharmony_ci			HFC_outb(hc, A_CONF,
291062306a36Sopenharmony_ci				 (conf < 0) ? 0 : (conf | V_CONF_SL));
291162306a36Sopenharmony_ci		hc->slot_owner[slot_tx << 1] = ch;
291262306a36Sopenharmony_ci		hc->chan[ch].slot_tx = slot_tx;
291362306a36Sopenharmony_ci		hc->chan[ch].bank_tx = bank_tx;
291462306a36Sopenharmony_ci	}
291562306a36Sopenharmony_ci	if (slot_rx < 0) {
291662306a36Sopenharmony_ci		/* disable pcm slot */
291762306a36Sopenharmony_ci		flow_rx = 0x80; /* ST->FIFO */
291862306a36Sopenharmony_ci		hc->chan[ch].slot_rx = -1;
291962306a36Sopenharmony_ci		hc->chan[ch].bank_rx = 0;
292062306a36Sopenharmony_ci	} else {
292162306a36Sopenharmony_ci		/* set pcm slot */
292262306a36Sopenharmony_ci		if (hc->chan[ch].txpending)
292362306a36Sopenharmony_ci			flow_rx = 0x80; /* ST->FIFO */
292462306a36Sopenharmony_ci		else
292562306a36Sopenharmony_ci			flow_rx = 0xc0; /* ST->(FIFO,PCM) */
292662306a36Sopenharmony_ci		/* put on slot */
292762306a36Sopenharmony_ci		routing = bank_rx ? 0x80 : 0xc0; /* reversed */
292862306a36Sopenharmony_ci		if (conf >= 0 || bank_rx > 1)
292962306a36Sopenharmony_ci			routing = 0x40; /* loop */
293062306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
293162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: put channel %d to slot %d bank"
293262306a36Sopenharmony_ci			       " %d flow %02x routing %02x conf %d (RX)\n",
293362306a36Sopenharmony_ci			       __func__, ch, slot_rx, bank_rx,
293462306a36Sopenharmony_ci			       flow_rx, routing, conf);
293562306a36Sopenharmony_ci		HFC_outb(hc, R_SLOT, (slot_rx << 1) | V_SL_DIR);
293662306a36Sopenharmony_ci		HFC_outb(hc, A_SL_CFG, (ch << 1) | V_CH_DIR | routing);
293762306a36Sopenharmony_ci		hc->slot_owner[(slot_rx << 1) | 1] = ch;
293862306a36Sopenharmony_ci		hc->chan[ch].slot_rx = slot_rx;
293962306a36Sopenharmony_ci		hc->chan[ch].bank_rx = bank_rx;
294062306a36Sopenharmony_ci	}
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci	switch (protocol) {
294362306a36Sopenharmony_ci	case (ISDN_P_NONE):
294462306a36Sopenharmony_ci		/* disable TX fifo */
294562306a36Sopenharmony_ci		HFC_outb(hc, R_FIFO, ch << 1);
294662306a36Sopenharmony_ci		HFC_wait(hc);
294762306a36Sopenharmony_ci		HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF);
294862306a36Sopenharmony_ci		HFC_outb(hc, A_SUBCH_CFG, 0);
294962306a36Sopenharmony_ci		HFC_outb(hc, A_IRQ_MSK, 0);
295062306a36Sopenharmony_ci		HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
295162306a36Sopenharmony_ci		HFC_wait(hc);
295262306a36Sopenharmony_ci		/* disable RX fifo */
295362306a36Sopenharmony_ci		HFC_outb(hc, R_FIFO, (ch << 1) | 1);
295462306a36Sopenharmony_ci		HFC_wait(hc);
295562306a36Sopenharmony_ci		HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00);
295662306a36Sopenharmony_ci		HFC_outb(hc, A_SUBCH_CFG, 0);
295762306a36Sopenharmony_ci		HFC_outb(hc, A_IRQ_MSK, 0);
295862306a36Sopenharmony_ci		HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
295962306a36Sopenharmony_ci		HFC_wait(hc);
296062306a36Sopenharmony_ci		if (hc->chan[ch].bch && hc->ctype != HFC_TYPE_E1) {
296162306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[hc->chan[ch].port] &=
296262306a36Sopenharmony_ci				((ch & 0x3) == 0) ? ~V_B1_EN : ~V_B2_EN;
296362306a36Sopenharmony_ci			HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
296462306a36Sopenharmony_ci			/* undocumented: delay after R_ST_SEL */
296562306a36Sopenharmony_ci			udelay(1);
296662306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CTRL0,
296762306a36Sopenharmony_ci				 hc->hw.a_st_ctrl0[hc->chan[ch].port]);
296862306a36Sopenharmony_ci		}
296962306a36Sopenharmony_ci		if (hc->chan[ch].bch) {
297062306a36Sopenharmony_ci			test_and_clear_bit(FLG_HDLC, &hc->chan[ch].bch->Flags);
297162306a36Sopenharmony_ci			test_and_clear_bit(FLG_TRANSPARENT,
297262306a36Sopenharmony_ci					   &hc->chan[ch].bch->Flags);
297362306a36Sopenharmony_ci		}
297462306a36Sopenharmony_ci		break;
297562306a36Sopenharmony_ci	case (ISDN_P_B_RAW): /* B-channel */
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
297862306a36Sopenharmony_ci		    (hc->chan[ch].slot_rx < 0) &&
297962306a36Sopenharmony_ci		    (hc->chan[ch].slot_tx < 0)) {
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci			printk(KERN_DEBUG
298262306a36Sopenharmony_ci			       "Setting B-channel %d to echo cancelable "
298362306a36Sopenharmony_ci			       "state on PCM slot %d\n", ch,
298462306a36Sopenharmony_ci			       ((ch / 4) * 8) + ((ch % 4) * 4) + 1);
298562306a36Sopenharmony_ci			printk(KERN_DEBUG
298662306a36Sopenharmony_ci			       "Enabling pass through for channel\n");
298762306a36Sopenharmony_ci			vpm_out(hc, ch, ((ch / 4) * 8) +
298862306a36Sopenharmony_ci				((ch % 4) * 4) + 1, 0x01);
298962306a36Sopenharmony_ci			/* rx path */
299062306a36Sopenharmony_ci			/* S/T -> PCM */
299162306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, (ch << 1));
299262306a36Sopenharmony_ci			HFC_wait(hc);
299362306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
299462306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
299562306a36Sopenharmony_ci					      ((ch % 4) * 4) + 1) << 1);
299662306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0x80 | (ch << 1));
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci			/* PCM -> FIFO */
299962306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, 0x20 | (ch << 1) | 1);
300062306a36Sopenharmony_ci			HFC_wait(hc);
300162306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
300262306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0);
300362306a36Sopenharmony_ci			HFC_outb(hc, A_IRQ_MSK, 0);
300462306a36Sopenharmony_ci			if (hc->chan[ch].protocol != protocol) {
300562306a36Sopenharmony_ci				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
300662306a36Sopenharmony_ci				HFC_wait(hc);
300762306a36Sopenharmony_ci			}
300862306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
300962306a36Sopenharmony_ci					       ((ch % 4) * 4) + 1) << 1) | 1);
301062306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1);
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci			/* tx path */
301362306a36Sopenharmony_ci			/* PCM -> S/T */
301462306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, (ch << 1) | 1);
301562306a36Sopenharmony_ci			HFC_wait(hc);
301662306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0xc0 | V_HDLC_TRP | V_IFF);
301762306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
301862306a36Sopenharmony_ci					       ((ch % 4) * 4)) << 1) | 1);
301962306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0x80 | 0x40 | (ch << 1) | 1);
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci			/* FIFO -> PCM */
302262306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, 0x20 | (ch << 1));
302362306a36Sopenharmony_ci			HFC_wait(hc);
302462306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
302562306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0);
302662306a36Sopenharmony_ci			HFC_outb(hc, A_IRQ_MSK, 0);
302762306a36Sopenharmony_ci			if (hc->chan[ch].protocol != protocol) {
302862306a36Sopenharmony_ci				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
302962306a36Sopenharmony_ci				HFC_wait(hc);
303062306a36Sopenharmony_ci			}
303162306a36Sopenharmony_ci			/* tx silence */
303262306a36Sopenharmony_ci			HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
303362306a36Sopenharmony_ci			HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
303462306a36Sopenharmony_ci					      ((ch % 4) * 4)) << 1);
303562306a36Sopenharmony_ci			HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1));
303662306a36Sopenharmony_ci		} else {
303762306a36Sopenharmony_ci			/* enable TX fifo */
303862306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, ch << 1);
303962306a36Sopenharmony_ci			HFC_wait(hc);
304062306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_XHFC)
304162306a36Sopenharmony_ci				HFC_outb(hc, A_CON_HDLC, flow_tx | 0x07 << 2 |
304262306a36Sopenharmony_ci					 V_HDLC_TRP | V_IFF);
304362306a36Sopenharmony_ci			/* Enable FIFO, no interrupt */
304462306a36Sopenharmony_ci			else
304562306a36Sopenharmony_ci				HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 |
304662306a36Sopenharmony_ci					 V_HDLC_TRP | V_IFF);
304762306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0);
304862306a36Sopenharmony_ci			HFC_outb(hc, A_IRQ_MSK, 0);
304962306a36Sopenharmony_ci			if (hc->chan[ch].protocol != protocol) {
305062306a36Sopenharmony_ci				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
305162306a36Sopenharmony_ci				HFC_wait(hc);
305262306a36Sopenharmony_ci			}
305362306a36Sopenharmony_ci			/* tx silence */
305462306a36Sopenharmony_ci			HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
305562306a36Sopenharmony_ci			/* enable RX fifo */
305662306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, (ch << 1) | 1);
305762306a36Sopenharmony_ci			HFC_wait(hc);
305862306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_XHFC)
305962306a36Sopenharmony_ci				HFC_outb(hc, A_CON_HDLC, flow_rx | 0x07 << 2 |
306062306a36Sopenharmony_ci					 V_HDLC_TRP);
306162306a36Sopenharmony_ci			/* Enable FIFO, no interrupt*/
306262306a36Sopenharmony_ci			else
306362306a36Sopenharmony_ci				HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 |
306462306a36Sopenharmony_ci					 V_HDLC_TRP);
306562306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0);
306662306a36Sopenharmony_ci			HFC_outb(hc, A_IRQ_MSK, 0);
306762306a36Sopenharmony_ci			if (hc->chan[ch].protocol != protocol) {
306862306a36Sopenharmony_ci				HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
306962306a36Sopenharmony_ci				HFC_wait(hc);
307062306a36Sopenharmony_ci			}
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_E1) {
307362306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
307462306a36Sopenharmony_ci				((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN;
307562306a36Sopenharmony_ci			HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
307662306a36Sopenharmony_ci			/* undocumented: delay after R_ST_SEL */
307762306a36Sopenharmony_ci			udelay(1);
307862306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CTRL0,
307962306a36Sopenharmony_ci				 hc->hw.a_st_ctrl0[hc->chan[ch].port]);
308062306a36Sopenharmony_ci		}
308162306a36Sopenharmony_ci		if (hc->chan[ch].bch)
308262306a36Sopenharmony_ci			test_and_set_bit(FLG_TRANSPARENT,
308362306a36Sopenharmony_ci					 &hc->chan[ch].bch->Flags);
308462306a36Sopenharmony_ci		break;
308562306a36Sopenharmony_ci	case (ISDN_P_B_HDLC): /* B-channel */
308662306a36Sopenharmony_ci	case (ISDN_P_TE_S0): /* D-channel */
308762306a36Sopenharmony_ci	case (ISDN_P_NT_S0):
308862306a36Sopenharmony_ci	case (ISDN_P_TE_E1):
308962306a36Sopenharmony_ci	case (ISDN_P_NT_E1):
309062306a36Sopenharmony_ci		/* enable TX fifo */
309162306a36Sopenharmony_ci		HFC_outb(hc, R_FIFO, ch << 1);
309262306a36Sopenharmony_ci		HFC_wait(hc);
309362306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch) {
309462306a36Sopenharmony_ci			/* E1 or B-channel */
309562306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04);
309662306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0);
309762306a36Sopenharmony_ci		} else {
309862306a36Sopenharmony_ci			/* D-Channel without HDLC fill flags */
309962306a36Sopenharmony_ci			HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF);
310062306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 2);
310162306a36Sopenharmony_ci		}
310262306a36Sopenharmony_ci		HFC_outb(hc, A_IRQ_MSK, V_IRQ);
310362306a36Sopenharmony_ci		HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
310462306a36Sopenharmony_ci		HFC_wait(hc);
310562306a36Sopenharmony_ci		/* enable RX fifo */
310662306a36Sopenharmony_ci		HFC_outb(hc, R_FIFO, (ch << 1) | 1);
310762306a36Sopenharmony_ci		HFC_wait(hc);
310862306a36Sopenharmony_ci		HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04);
310962306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1 || hc->chan[ch].bch)
311062306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 0); /* full 8 bits */
311162306a36Sopenharmony_ci		else
311262306a36Sopenharmony_ci			HFC_outb(hc, A_SUBCH_CFG, 2); /* 2 bits dchannel */
311362306a36Sopenharmony_ci		HFC_outb(hc, A_IRQ_MSK, V_IRQ);
311462306a36Sopenharmony_ci		HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
311562306a36Sopenharmony_ci		HFC_wait(hc);
311662306a36Sopenharmony_ci		if (hc->chan[ch].bch) {
311762306a36Sopenharmony_ci			test_and_set_bit(FLG_HDLC, &hc->chan[ch].bch->Flags);
311862306a36Sopenharmony_ci			if (hc->ctype != HFC_TYPE_E1) {
311962306a36Sopenharmony_ci				hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
312062306a36Sopenharmony_ci					((ch & 0x3) == 0) ? V_B1_EN : V_B2_EN;
312162306a36Sopenharmony_ci				HFC_outb(hc, R_ST_SEL, hc->chan[ch].port);
312262306a36Sopenharmony_ci				/* undocumented: delay after R_ST_SEL */
312362306a36Sopenharmony_ci				udelay(1);
312462306a36Sopenharmony_ci				HFC_outb(hc, A_ST_CTRL0,
312562306a36Sopenharmony_ci					 hc->hw.a_st_ctrl0[hc->chan[ch].port]);
312662306a36Sopenharmony_ci			}
312762306a36Sopenharmony_ci		}
312862306a36Sopenharmony_ci		break;
312962306a36Sopenharmony_ci	default:
313062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: protocol not known %x\n",
313162306a36Sopenharmony_ci		       __func__, protocol);
313262306a36Sopenharmony_ci		hc->chan[ch].protocol = ISDN_P_NONE;
313362306a36Sopenharmony_ci		return -ENOPROTOOPT;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci	hc->chan[ch].protocol = protocol;
313662306a36Sopenharmony_ci	return 0;
313762306a36Sopenharmony_ci}
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci/*
314162306a36Sopenharmony_ci * connect/disconnect PCM
314262306a36Sopenharmony_ci */
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_cistatic void
314562306a36Sopenharmony_cihfcmulti_pcm(struct hfc_multi *hc, int ch, int slot_tx, int bank_tx,
314662306a36Sopenharmony_ci	     int slot_rx, int bank_rx)
314762306a36Sopenharmony_ci{
314862306a36Sopenharmony_ci	if (slot_tx < 0 || slot_rx < 0 || bank_tx < 0 || bank_rx < 0) {
314962306a36Sopenharmony_ci		/* disable PCM */
315062306a36Sopenharmony_ci		mode_hfcmulti(hc, ch, hc->chan[ch].protocol, -1, 0, -1, 0);
315162306a36Sopenharmony_ci		return;
315262306a36Sopenharmony_ci	}
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	/* enable pcm */
315562306a36Sopenharmony_ci	mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx,
315662306a36Sopenharmony_ci		      slot_rx, bank_rx);
315762306a36Sopenharmony_ci}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci/*
316062306a36Sopenharmony_ci * set/disable conference
316162306a36Sopenharmony_ci */
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_cistatic void
316462306a36Sopenharmony_cihfcmulti_conf(struct hfc_multi *hc, int ch, int num)
316562306a36Sopenharmony_ci{
316662306a36Sopenharmony_ci	if (num >= 0 && num <= 7)
316762306a36Sopenharmony_ci		hc->chan[ch].conf = num;
316862306a36Sopenharmony_ci	else
316962306a36Sopenharmony_ci		hc->chan[ch].conf = -1;
317062306a36Sopenharmony_ci	mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx,
317162306a36Sopenharmony_ci		      hc->chan[ch].bank_tx, hc->chan[ch].slot_rx,
317262306a36Sopenharmony_ci		      hc->chan[ch].bank_rx);
317362306a36Sopenharmony_ci}
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci/*
317762306a36Sopenharmony_ci * set/disable sample loop
317862306a36Sopenharmony_ci */
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci/* NOTE: this function is experimental and therefore disabled */
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci/*
318362306a36Sopenharmony_ci * Layer 1 callback function
318462306a36Sopenharmony_ci */
318562306a36Sopenharmony_cistatic int
318662306a36Sopenharmony_cihfcm_l1callback(struct dchannel *dch, u_int cmd)
318762306a36Sopenharmony_ci{
318862306a36Sopenharmony_ci	struct hfc_multi	*hc = dch->hw;
318962306a36Sopenharmony_ci	struct sk_buff_head	free_queue;
319062306a36Sopenharmony_ci	u_long	flags;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	switch (cmd) {
319362306a36Sopenharmony_ci	case INFO3_P8:
319462306a36Sopenharmony_ci	case INFO3_P10:
319562306a36Sopenharmony_ci		break;
319662306a36Sopenharmony_ci	case HW_RESET_REQ:
319762306a36Sopenharmony_ci		/* start activation */
319862306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
319962306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1) {
320062306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
320162306a36Sopenharmony_ci				printk(KERN_DEBUG
320262306a36Sopenharmony_ci				       "%s: HW_RESET_REQ no BRI\n",
320362306a36Sopenharmony_ci				       __func__);
320462306a36Sopenharmony_ci		} else {
320562306a36Sopenharmony_ci			HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
320662306a36Sopenharmony_ci			/* undocumented: delay after R_ST_SEL */
320762306a36Sopenharmony_ci			udelay(1);
320862306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* F3 */
320962306a36Sopenharmony_ci			udelay(6); /* wait at least 5,21us */
321062306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, 3);
321162306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT * 3));
321262306a36Sopenharmony_ci			/* activate */
321362306a36Sopenharmony_ci		}
321462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
321562306a36Sopenharmony_ci		l1_event(dch->l1, HW_POWERUP_IND);
321662306a36Sopenharmony_ci		break;
321762306a36Sopenharmony_ci	case HW_DEACT_REQ:
321862306a36Sopenharmony_ci		__skb_queue_head_init(&free_queue);
321962306a36Sopenharmony_ci		/* start deactivation */
322062306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
322162306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1) {
322262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
322362306a36Sopenharmony_ci				printk(KERN_DEBUG
322462306a36Sopenharmony_ci				       "%s: HW_DEACT_REQ no BRI\n",
322562306a36Sopenharmony_ci				       __func__);
322662306a36Sopenharmony_ci		} else {
322762306a36Sopenharmony_ci			HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
322862306a36Sopenharmony_ci			/* undocumented: delay after R_ST_SEL */
322962306a36Sopenharmony_ci			udelay(1);
323062306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2);
323162306a36Sopenharmony_ci			/* deactivate */
323262306a36Sopenharmony_ci			if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
323362306a36Sopenharmony_ci				hc->syncronized &=
323462306a36Sopenharmony_ci					~(1 << hc->chan[dch->slot].port);
323562306a36Sopenharmony_ci				plxsd_checksync(hc, 0);
323662306a36Sopenharmony_ci			}
323762306a36Sopenharmony_ci		}
323862306a36Sopenharmony_ci		skb_queue_splice_init(&dch->squeue, &free_queue);
323962306a36Sopenharmony_ci		if (dch->tx_skb) {
324062306a36Sopenharmony_ci			__skb_queue_tail(&free_queue, dch->tx_skb);
324162306a36Sopenharmony_ci			dch->tx_skb = NULL;
324262306a36Sopenharmony_ci		}
324362306a36Sopenharmony_ci		dch->tx_idx = 0;
324462306a36Sopenharmony_ci		if (dch->rx_skb) {
324562306a36Sopenharmony_ci			__skb_queue_tail(&free_queue, dch->rx_skb);
324662306a36Sopenharmony_ci			dch->rx_skb = NULL;
324762306a36Sopenharmony_ci		}
324862306a36Sopenharmony_ci		test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
324962306a36Sopenharmony_ci		if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
325062306a36Sopenharmony_ci			del_timer(&dch->timer);
325162306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
325262306a36Sopenharmony_ci		__skb_queue_purge(&free_queue);
325362306a36Sopenharmony_ci		break;
325462306a36Sopenharmony_ci	case HW_POWERUP_REQ:
325562306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
325662306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1) {
325762306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
325862306a36Sopenharmony_ci				printk(KERN_DEBUG
325962306a36Sopenharmony_ci				       "%s: HW_POWERUP_REQ no BRI\n",
326062306a36Sopenharmony_ci				       __func__);
326162306a36Sopenharmony_ci		} else {
326262306a36Sopenharmony_ci			HFC_outb(hc, R_ST_SEL, hc->chan[dch->slot].port);
326362306a36Sopenharmony_ci			/* undocumented: delay after R_ST_SEL */
326462306a36Sopenharmony_ci			udelay(1);
326562306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */
326662306a36Sopenharmony_ci			udelay(6); /* wait at least 5,21us */
326762306a36Sopenharmony_ci			HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */
326862306a36Sopenharmony_ci		}
326962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
327062306a36Sopenharmony_ci		break;
327162306a36Sopenharmony_ci	case PH_ACTIVATE_IND:
327262306a36Sopenharmony_ci		test_and_set_bit(FLG_ACTIVE, &dch->Flags);
327362306a36Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
327462306a36Sopenharmony_ci			    GFP_ATOMIC);
327562306a36Sopenharmony_ci		break;
327662306a36Sopenharmony_ci	case PH_DEACTIVATE_IND:
327762306a36Sopenharmony_ci		test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
327862306a36Sopenharmony_ci		_queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
327962306a36Sopenharmony_ci			    GFP_ATOMIC);
328062306a36Sopenharmony_ci		break;
328162306a36Sopenharmony_ci	default:
328262306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW)
328362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
328462306a36Sopenharmony_ci			       __func__, cmd);
328562306a36Sopenharmony_ci		return -1;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci	return 0;
328862306a36Sopenharmony_ci}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci/*
329162306a36Sopenharmony_ci * Layer2 -> Layer 1 Transfer
329262306a36Sopenharmony_ci */
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_cistatic int
329562306a36Sopenharmony_cihandle_dmsg(struct mISDNchannel *ch, struct sk_buff *skb)
329662306a36Sopenharmony_ci{
329762306a36Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
329862306a36Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
329962306a36Sopenharmony_ci	struct hfc_multi	*hc = dch->hw;
330062306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
330162306a36Sopenharmony_ci	int			ret = -EINVAL;
330262306a36Sopenharmony_ci	unsigned int		id;
330362306a36Sopenharmony_ci	u_long			flags;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	switch (hh->prim) {
330662306a36Sopenharmony_ci	case PH_DATA_REQ:
330762306a36Sopenharmony_ci		if (skb->len < 1)
330862306a36Sopenharmony_ci			break;
330962306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
331062306a36Sopenharmony_ci		ret = dchannel_senddata(dch, skb);
331162306a36Sopenharmony_ci		if (ret > 0) { /* direct TX */
331262306a36Sopenharmony_ci			id = hh->id; /* skb can be freed */
331362306a36Sopenharmony_ci			hfcmulti_tx(hc, dch->slot);
331462306a36Sopenharmony_ci			ret = 0;
331562306a36Sopenharmony_ci			/* start fifo */
331662306a36Sopenharmony_ci			HFC_outb(hc, R_FIFO, 0);
331762306a36Sopenharmony_ci			HFC_wait(hc);
331862306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
331962306a36Sopenharmony_ci			queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
332062306a36Sopenharmony_ci		} else
332162306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
332262306a36Sopenharmony_ci		return ret;
332362306a36Sopenharmony_ci	case PH_ACTIVATE_REQ:
332462306a36Sopenharmony_ci		if (dch->dev.D.protocol != ISDN_P_TE_S0) {
332562306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
332662306a36Sopenharmony_ci			ret = 0;
332762306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
332862306a36Sopenharmony_ci				printk(KERN_DEBUG
332962306a36Sopenharmony_ci				       "%s: PH_ACTIVATE port %d (0..%d)\n",
333062306a36Sopenharmony_ci				       __func__, hc->chan[dch->slot].port,
333162306a36Sopenharmony_ci				       hc->ports - 1);
333262306a36Sopenharmony_ci			/* start activation */
333362306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_E1) {
333462306a36Sopenharmony_ci				ph_state_change(dch);
333562306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_STATE)
333662306a36Sopenharmony_ci					printk(KERN_DEBUG
333762306a36Sopenharmony_ci					       "%s: E1 report state %x \n",
333862306a36Sopenharmony_ci					       __func__, dch->state);
333962306a36Sopenharmony_ci			} else {
334062306a36Sopenharmony_ci				HFC_outb(hc, R_ST_SEL,
334162306a36Sopenharmony_ci					 hc->chan[dch->slot].port);
334262306a36Sopenharmony_ci				/* undocumented: delay after R_ST_SEL */
334362306a36Sopenharmony_ci				udelay(1);
334462306a36Sopenharmony_ci				HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1);
334562306a36Sopenharmony_ci				/* G1 */
334662306a36Sopenharmony_ci				udelay(6); /* wait at least 5,21us */
334762306a36Sopenharmony_ci				HFC_outb(hc, A_ST_WR_STATE, 1);
334862306a36Sopenharmony_ci				HFC_outb(hc, A_ST_WR_STATE, 1 |
334962306a36Sopenharmony_ci					 (V_ST_ACT * 3)); /* activate */
335062306a36Sopenharmony_ci				dch->state = 1;
335162306a36Sopenharmony_ci			}
335262306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
335362306a36Sopenharmony_ci		} else
335462306a36Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
335562306a36Sopenharmony_ci		break;
335662306a36Sopenharmony_ci	case PH_DEACTIVATE_REQ:
335762306a36Sopenharmony_ci		test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
335862306a36Sopenharmony_ci		if (dch->dev.D.protocol != ISDN_P_TE_S0) {
335962306a36Sopenharmony_ci			struct sk_buff_head free_queue;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci			__skb_queue_head_init(&free_queue);
336262306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
336362306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
336462306a36Sopenharmony_ci				printk(KERN_DEBUG
336562306a36Sopenharmony_ci				       "%s: PH_DEACTIVATE port %d (0..%d)\n",
336662306a36Sopenharmony_ci				       __func__, hc->chan[dch->slot].port,
336762306a36Sopenharmony_ci				       hc->ports - 1);
336862306a36Sopenharmony_ci			/* start deactivation */
336962306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_E1) {
337062306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_MSG)
337162306a36Sopenharmony_ci					printk(KERN_DEBUG
337262306a36Sopenharmony_ci					       "%s: PH_DEACTIVATE no BRI\n",
337362306a36Sopenharmony_ci					       __func__);
337462306a36Sopenharmony_ci			} else {
337562306a36Sopenharmony_ci				HFC_outb(hc, R_ST_SEL,
337662306a36Sopenharmony_ci					 hc->chan[dch->slot].port);
337762306a36Sopenharmony_ci				/* undocumented: delay after R_ST_SEL */
337862306a36Sopenharmony_ci				udelay(1);
337962306a36Sopenharmony_ci				HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT * 2);
338062306a36Sopenharmony_ci				/* deactivate */
338162306a36Sopenharmony_ci				dch->state = 1;
338262306a36Sopenharmony_ci			}
338362306a36Sopenharmony_ci			skb_queue_splice_init(&dch->squeue, &free_queue);
338462306a36Sopenharmony_ci			if (dch->tx_skb) {
338562306a36Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->tx_skb);
338662306a36Sopenharmony_ci				dch->tx_skb = NULL;
338762306a36Sopenharmony_ci			}
338862306a36Sopenharmony_ci			dch->tx_idx = 0;
338962306a36Sopenharmony_ci			if (dch->rx_skb) {
339062306a36Sopenharmony_ci				__skb_queue_tail(&free_queue, dch->rx_skb);
339162306a36Sopenharmony_ci				dch->rx_skb = NULL;
339262306a36Sopenharmony_ci			}
339362306a36Sopenharmony_ci			test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
339462306a36Sopenharmony_ci			if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
339562306a36Sopenharmony_ci				del_timer(&dch->timer);
339662306a36Sopenharmony_ci#ifdef FIXME
339762306a36Sopenharmony_ci			if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
339862306a36Sopenharmony_ci				dchannel_sched_event(&hc->dch, D_CLEARBUSY);
339962306a36Sopenharmony_ci#endif
340062306a36Sopenharmony_ci			ret = 0;
340162306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
340262306a36Sopenharmony_ci			__skb_queue_purge(&free_queue);
340362306a36Sopenharmony_ci		} else
340462306a36Sopenharmony_ci			ret = l1_event(dch->l1, hh->prim);
340562306a36Sopenharmony_ci		break;
340662306a36Sopenharmony_ci	}
340762306a36Sopenharmony_ci	if (!ret)
340862306a36Sopenharmony_ci		dev_kfree_skb(skb);
340962306a36Sopenharmony_ci	return ret;
341062306a36Sopenharmony_ci}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_cistatic void
341362306a36Sopenharmony_cideactivate_bchannel(struct bchannel *bch)
341462306a36Sopenharmony_ci{
341562306a36Sopenharmony_ci	struct hfc_multi	*hc = bch->hw;
341662306a36Sopenharmony_ci	u_long			flags;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
341962306a36Sopenharmony_ci	mISDN_clear_bchannel(bch);
342062306a36Sopenharmony_ci	hc->chan[bch->slot].coeff_count = 0;
342162306a36Sopenharmony_ci	hc->chan[bch->slot].rx_off = 0;
342262306a36Sopenharmony_ci	hc->chan[bch->slot].conf = -1;
342362306a36Sopenharmony_ci	mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0);
342462306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
342562306a36Sopenharmony_ci}
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_cistatic int
342862306a36Sopenharmony_cihandle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
342962306a36Sopenharmony_ci{
343062306a36Sopenharmony_ci	struct bchannel		*bch = container_of(ch, struct bchannel, ch);
343162306a36Sopenharmony_ci	struct hfc_multi	*hc = bch->hw;
343262306a36Sopenharmony_ci	int			ret = -EINVAL;
343362306a36Sopenharmony_ci	struct mISDNhead	*hh = mISDN_HEAD_P(skb);
343462306a36Sopenharmony_ci	unsigned long		flags;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	switch (hh->prim) {
343762306a36Sopenharmony_ci	case PH_DATA_REQ:
343862306a36Sopenharmony_ci		if (!skb->len)
343962306a36Sopenharmony_ci			break;
344062306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
344162306a36Sopenharmony_ci		ret = bchannel_senddata(bch, skb);
344262306a36Sopenharmony_ci		if (ret > 0) { /* direct TX */
344362306a36Sopenharmony_ci			hfcmulti_tx(hc, bch->slot);
344462306a36Sopenharmony_ci			ret = 0;
344562306a36Sopenharmony_ci			/* start fifo */
344662306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_FIFO, 0);
344762306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
344862306a36Sopenharmony_ci		}
344962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
345062306a36Sopenharmony_ci		return ret;
345162306a36Sopenharmony_ci	case PH_ACTIVATE_REQ:
345262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
345362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n",
345462306a36Sopenharmony_ci			       __func__, bch->slot);
345562306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
345662306a36Sopenharmony_ci		/* activate B-channel if not already activated */
345762306a36Sopenharmony_ci		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
345862306a36Sopenharmony_ci			hc->chan[bch->slot].txpending = 0;
345962306a36Sopenharmony_ci			ret = mode_hfcmulti(hc, bch->slot,
346062306a36Sopenharmony_ci					    ch->protocol,
346162306a36Sopenharmony_ci					    hc->chan[bch->slot].slot_tx,
346262306a36Sopenharmony_ci					    hc->chan[bch->slot].bank_tx,
346362306a36Sopenharmony_ci					    hc->chan[bch->slot].slot_rx,
346462306a36Sopenharmony_ci					    hc->chan[bch->slot].bank_rx);
346562306a36Sopenharmony_ci			if (!ret) {
346662306a36Sopenharmony_ci				if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf
346762306a36Sopenharmony_ci				    && test_bit(HFC_CHIP_DTMF, &hc->chip)) {
346862306a36Sopenharmony_ci					/* start decoder */
346962306a36Sopenharmony_ci					hc->dtmf = 1;
347062306a36Sopenharmony_ci					if (debug & DEBUG_HFCMULTI_DTMF)
347162306a36Sopenharmony_ci						printk(KERN_DEBUG
347262306a36Sopenharmony_ci						       "%s: start dtmf decoder\n",
347362306a36Sopenharmony_ci						       __func__);
347462306a36Sopenharmony_ci					HFC_outb(hc, R_DTMF, hc->hw.r_dtmf |
347562306a36Sopenharmony_ci						 V_RST_DTMF);
347662306a36Sopenharmony_ci				}
347762306a36Sopenharmony_ci			}
347862306a36Sopenharmony_ci		} else
347962306a36Sopenharmony_ci			ret = 0;
348062306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
348162306a36Sopenharmony_ci		if (!ret)
348262306a36Sopenharmony_ci			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
348362306a36Sopenharmony_ci				    GFP_KERNEL);
348462306a36Sopenharmony_ci		break;
348562306a36Sopenharmony_ci	case PH_CONTROL_REQ:
348662306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
348762306a36Sopenharmony_ci		switch (hh->id) {
348862306a36Sopenharmony_ci		case HFC_SPL_LOOP_ON: /* set sample loop */
348962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
349062306a36Sopenharmony_ci				printk(KERN_DEBUG
349162306a36Sopenharmony_ci				       "%s: HFC_SPL_LOOP_ON (len = %d)\n",
349262306a36Sopenharmony_ci				       __func__, skb->len);
349362306a36Sopenharmony_ci			ret = 0;
349462306a36Sopenharmony_ci			break;
349562306a36Sopenharmony_ci		case HFC_SPL_LOOP_OFF: /* set silence */
349662306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_MSG)
349762306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n",
349862306a36Sopenharmony_ci				       __func__);
349962306a36Sopenharmony_ci			ret = 0;
350062306a36Sopenharmony_ci			break;
350162306a36Sopenharmony_ci		default:
350262306a36Sopenharmony_ci			printk(KERN_ERR
350362306a36Sopenharmony_ci			       "%s: unknown PH_CONTROL_REQ info %x\n",
350462306a36Sopenharmony_ci			       __func__, hh->id);
350562306a36Sopenharmony_ci			ret = -EINVAL;
350662306a36Sopenharmony_ci		}
350762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
350862306a36Sopenharmony_ci		break;
350962306a36Sopenharmony_ci	case PH_DEACTIVATE_REQ:
351062306a36Sopenharmony_ci		deactivate_bchannel(bch); /* locked there */
351162306a36Sopenharmony_ci		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
351262306a36Sopenharmony_ci			    GFP_KERNEL);
351362306a36Sopenharmony_ci		ret = 0;
351462306a36Sopenharmony_ci		break;
351562306a36Sopenharmony_ci	}
351662306a36Sopenharmony_ci	if (!ret)
351762306a36Sopenharmony_ci		dev_kfree_skb(skb);
351862306a36Sopenharmony_ci	return ret;
351962306a36Sopenharmony_ci}
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci/*
352262306a36Sopenharmony_ci * bchannel control function
352362306a36Sopenharmony_ci */
352462306a36Sopenharmony_cistatic int
352562306a36Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
352662306a36Sopenharmony_ci{
352762306a36Sopenharmony_ci	int			ret = 0;
352862306a36Sopenharmony_ci	struct dsp_features	*features =
352962306a36Sopenharmony_ci		(struct dsp_features *)(*((u_long *)&cq->p1));
353062306a36Sopenharmony_ci	struct hfc_multi	*hc = bch->hw;
353162306a36Sopenharmony_ci	int			slot_tx;
353262306a36Sopenharmony_ci	int			bank_tx;
353362306a36Sopenharmony_ci	int			slot_rx;
353462306a36Sopenharmony_ci	int			bank_rx;
353562306a36Sopenharmony_ci	int			num;
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	switch (cq->op) {
353862306a36Sopenharmony_ci	case MISDN_CTRL_GETOP:
353962306a36Sopenharmony_ci		ret = mISDN_ctrl_bchannel(bch, cq);
354062306a36Sopenharmony_ci		cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP;
354162306a36Sopenharmony_ci		break;
354262306a36Sopenharmony_ci	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
354362306a36Sopenharmony_ci		ret = mISDN_ctrl_bchannel(bch, cq);
354462306a36Sopenharmony_ci		hc->chan[bch->slot].rx_off = !!cq->p1;
354562306a36Sopenharmony_ci		if (!hc->chan[bch->slot].rx_off) {
354662306a36Sopenharmony_ci			/* reset fifo on rx on */
354762306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1);
354862306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
354962306a36Sopenharmony_ci			HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
355062306a36Sopenharmony_ci			HFC_wait_nodebug(hc);
355162306a36Sopenharmony_ci		}
355262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
355362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
355462306a36Sopenharmony_ci			       __func__, bch->nr, hc->chan[bch->slot].rx_off);
355562306a36Sopenharmony_ci		break;
355662306a36Sopenharmony_ci	case MISDN_CTRL_FILL_EMPTY:
355762306a36Sopenharmony_ci		ret = mISDN_ctrl_bchannel(bch, cq);
355862306a36Sopenharmony_ci		hc->silence = bch->fill[0];
355962306a36Sopenharmony_ci		memset(hc->silence_data, hc->silence, sizeof(hc->silence_data));
356062306a36Sopenharmony_ci		break;
356162306a36Sopenharmony_ci	case MISDN_CTRL_HW_FEATURES: /* fill features structure */
356262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
356362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HW_FEATURE request\n",
356462306a36Sopenharmony_ci			       __func__);
356562306a36Sopenharmony_ci		/* create confirm */
356662306a36Sopenharmony_ci		features->hfc_id = hc->id;
356762306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_DTMF, &hc->chip))
356862306a36Sopenharmony_ci			features->hfc_dtmf = 1;
356962306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_CONF, &hc->chip))
357062306a36Sopenharmony_ci			features->hfc_conf = 1;
357162306a36Sopenharmony_ci		features->hfc_loops = 0;
357262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
357362306a36Sopenharmony_ci			features->hfc_echocanhw = 1;
357462306a36Sopenharmony_ci		} else {
357562306a36Sopenharmony_ci			features->pcm_id = hc->pcm;
357662306a36Sopenharmony_ci			features->pcm_slots = hc->slots;
357762306a36Sopenharmony_ci			features->pcm_banks = 2;
357862306a36Sopenharmony_ci		}
357962306a36Sopenharmony_ci		break;
358062306a36Sopenharmony_ci	case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */
358162306a36Sopenharmony_ci		slot_tx = cq->p1 & 0xff;
358262306a36Sopenharmony_ci		bank_tx = cq->p1 >> 8;
358362306a36Sopenharmony_ci		slot_rx = cq->p2 & 0xff;
358462306a36Sopenharmony_ci		bank_rx = cq->p2 >> 8;
358562306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
358662306a36Sopenharmony_ci			printk(KERN_DEBUG
358762306a36Sopenharmony_ci			       "%s: HFC_PCM_CONN slot %d bank %d (TX) "
358862306a36Sopenharmony_ci			       "slot %d bank %d (RX)\n",
358962306a36Sopenharmony_ci			       __func__, slot_tx, bank_tx,
359062306a36Sopenharmony_ci			       slot_rx, bank_rx);
359162306a36Sopenharmony_ci		if (slot_tx < hc->slots && bank_tx <= 2 &&
359262306a36Sopenharmony_ci		    slot_rx < hc->slots && bank_rx <= 2)
359362306a36Sopenharmony_ci			hfcmulti_pcm(hc, bch->slot,
359462306a36Sopenharmony_ci				     slot_tx, bank_tx, slot_rx, bank_rx);
359562306a36Sopenharmony_ci		else {
359662306a36Sopenharmony_ci			printk(KERN_WARNING
359762306a36Sopenharmony_ci			       "%s: HFC_PCM_CONN slot %d bank %d (TX) "
359862306a36Sopenharmony_ci			       "slot %d bank %d (RX) out of range\n",
359962306a36Sopenharmony_ci			       __func__, slot_tx, bank_tx,
360062306a36Sopenharmony_ci			       slot_rx, bank_rx);
360162306a36Sopenharmony_ci			ret = -EINVAL;
360262306a36Sopenharmony_ci		}
360362306a36Sopenharmony_ci		break;
360462306a36Sopenharmony_ci	case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */
360562306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
360662306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HFC_PCM_DISC\n",
360762306a36Sopenharmony_ci			       __func__);
360862306a36Sopenharmony_ci		hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0);
360962306a36Sopenharmony_ci		break;
361062306a36Sopenharmony_ci	case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */
361162306a36Sopenharmony_ci		num = cq->p1 & 0xff;
361262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
361362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n",
361462306a36Sopenharmony_ci			       __func__, num);
361562306a36Sopenharmony_ci		if (num <= 7)
361662306a36Sopenharmony_ci			hfcmulti_conf(hc, bch->slot, num);
361762306a36Sopenharmony_ci		else {
361862306a36Sopenharmony_ci			printk(KERN_WARNING
361962306a36Sopenharmony_ci			       "%s: HW_CONF_JOIN conf %d out of range\n",
362062306a36Sopenharmony_ci			       __func__, num);
362162306a36Sopenharmony_ci			ret = -EINVAL;
362262306a36Sopenharmony_ci		}
362362306a36Sopenharmony_ci		break;
362462306a36Sopenharmony_ci	case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */
362562306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
362662306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__);
362762306a36Sopenharmony_ci		hfcmulti_conf(hc, bch->slot, -1);
362862306a36Sopenharmony_ci		break;
362962306a36Sopenharmony_ci	case MISDN_CTRL_HFC_ECHOCAN_ON:
363062306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
363162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__);
363262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip))
363362306a36Sopenharmony_ci			vpm_echocan_on(hc, bch->slot, cq->p1);
363462306a36Sopenharmony_ci		else
363562306a36Sopenharmony_ci			ret = -EINVAL;
363662306a36Sopenharmony_ci		break;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	case MISDN_CTRL_HFC_ECHOCAN_OFF:
363962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
364062306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n",
364162306a36Sopenharmony_ci			       __func__);
364262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip))
364362306a36Sopenharmony_ci			vpm_echocan_off(hc, bch->slot);
364462306a36Sopenharmony_ci		else
364562306a36Sopenharmony_ci			ret = -EINVAL;
364662306a36Sopenharmony_ci		break;
364762306a36Sopenharmony_ci	default:
364862306a36Sopenharmony_ci		ret = mISDN_ctrl_bchannel(bch, cq);
364962306a36Sopenharmony_ci		break;
365062306a36Sopenharmony_ci	}
365162306a36Sopenharmony_ci	return ret;
365262306a36Sopenharmony_ci}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_cistatic int
365562306a36Sopenharmony_cihfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
365662306a36Sopenharmony_ci{
365762306a36Sopenharmony_ci	struct bchannel		*bch = container_of(ch, struct bchannel, ch);
365862306a36Sopenharmony_ci	struct hfc_multi	*hc = bch->hw;
365962306a36Sopenharmony_ci	int			err = -EINVAL;
366062306a36Sopenharmony_ci	u_long	flags;
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	if (bch->debug & DEBUG_HW)
366362306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n",
366462306a36Sopenharmony_ci		       __func__, cmd, arg);
366562306a36Sopenharmony_ci	switch (cmd) {
366662306a36Sopenharmony_ci	case CLOSE_CHANNEL:
366762306a36Sopenharmony_ci		test_and_clear_bit(FLG_OPEN, &bch->Flags);
366862306a36Sopenharmony_ci		deactivate_bchannel(bch); /* locked there */
366962306a36Sopenharmony_ci		ch->protocol = ISDN_P_NONE;
367062306a36Sopenharmony_ci		ch->peer = NULL;
367162306a36Sopenharmony_ci		module_put(THIS_MODULE);
367262306a36Sopenharmony_ci		err = 0;
367362306a36Sopenharmony_ci		break;
367462306a36Sopenharmony_ci	case CONTROL_CHANNEL:
367562306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
367662306a36Sopenharmony_ci		err = channel_bctrl(bch, arg);
367762306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
367862306a36Sopenharmony_ci		break;
367962306a36Sopenharmony_ci	default:
368062306a36Sopenharmony_ci		printk(KERN_WARNING "%s: unknown prim(%x)\n",
368162306a36Sopenharmony_ci		       __func__, cmd);
368262306a36Sopenharmony_ci	}
368362306a36Sopenharmony_ci	return err;
368462306a36Sopenharmony_ci}
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci/*
368762306a36Sopenharmony_ci * handle D-channel events
368862306a36Sopenharmony_ci *
368962306a36Sopenharmony_ci * handle state change event
369062306a36Sopenharmony_ci */
369162306a36Sopenharmony_cistatic void
369262306a36Sopenharmony_ciph_state_change(struct dchannel *dch)
369362306a36Sopenharmony_ci{
369462306a36Sopenharmony_ci	struct hfc_multi *hc;
369562306a36Sopenharmony_ci	int ch, i;
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	if (!dch) {
369862306a36Sopenharmony_ci		printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __func__);
369962306a36Sopenharmony_ci		return;
370062306a36Sopenharmony_ci	}
370162306a36Sopenharmony_ci	hc = dch->hw;
370262306a36Sopenharmony_ci	ch = dch->slot;
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1) {
370562306a36Sopenharmony_ci		if (dch->dev.D.protocol == ISDN_P_TE_E1) {
370662306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_STATE)
370762306a36Sopenharmony_ci				printk(KERN_DEBUG
370862306a36Sopenharmony_ci				       "%s: E1 TE (id=%d) newstate %x\n",
370962306a36Sopenharmony_ci				       __func__, hc->id, dch->state);
371062306a36Sopenharmony_ci		} else {
371162306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_STATE)
371262306a36Sopenharmony_ci				printk(KERN_DEBUG
371362306a36Sopenharmony_ci				       "%s: E1 NT (id=%d) newstate %x\n",
371462306a36Sopenharmony_ci				       __func__, hc->id, dch->state);
371562306a36Sopenharmony_ci		}
371662306a36Sopenharmony_ci		switch (dch->state) {
371762306a36Sopenharmony_ci		case (1):
371862306a36Sopenharmony_ci			if (hc->e1_state != 1) {
371962306a36Sopenharmony_ci				for (i = 1; i <= 31; i++) {
372062306a36Sopenharmony_ci					/* reset fifos on e1 activation */
372162306a36Sopenharmony_ci					HFC_outb_nodebug(hc, R_FIFO,
372262306a36Sopenharmony_ci							 (i << 1) | 1);
372362306a36Sopenharmony_ci					HFC_wait_nodebug(hc);
372462306a36Sopenharmony_ci					HFC_outb_nodebug(hc, R_INC_RES_FIFO,
372562306a36Sopenharmony_ci							 V_RES_F);
372662306a36Sopenharmony_ci					HFC_wait_nodebug(hc);
372762306a36Sopenharmony_ci				}
372862306a36Sopenharmony_ci			}
372962306a36Sopenharmony_ci			test_and_set_bit(FLG_ACTIVE, &dch->Flags);
373062306a36Sopenharmony_ci			_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
373162306a36Sopenharmony_ci				    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
373262306a36Sopenharmony_ci			break;
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci		default:
373562306a36Sopenharmony_ci			if (hc->e1_state != 1)
373662306a36Sopenharmony_ci				return;
373762306a36Sopenharmony_ci			test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
373862306a36Sopenharmony_ci			_queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
373962306a36Sopenharmony_ci				    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
374062306a36Sopenharmony_ci		}
374162306a36Sopenharmony_ci		hc->e1_state = dch->state;
374262306a36Sopenharmony_ci	} else {
374362306a36Sopenharmony_ci		if (dch->dev.D.protocol == ISDN_P_TE_S0) {
374462306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_STATE)
374562306a36Sopenharmony_ci				printk(KERN_DEBUG
374662306a36Sopenharmony_ci				       "%s: S/T TE newstate %x\n",
374762306a36Sopenharmony_ci				       __func__, dch->state);
374862306a36Sopenharmony_ci			switch (dch->state) {
374962306a36Sopenharmony_ci			case (0):
375062306a36Sopenharmony_ci				l1_event(dch->l1, HW_RESET_IND);
375162306a36Sopenharmony_ci				break;
375262306a36Sopenharmony_ci			case (3):
375362306a36Sopenharmony_ci				l1_event(dch->l1, HW_DEACT_IND);
375462306a36Sopenharmony_ci				break;
375562306a36Sopenharmony_ci			case (5):
375662306a36Sopenharmony_ci			case (8):
375762306a36Sopenharmony_ci				l1_event(dch->l1, ANYSIGNAL);
375862306a36Sopenharmony_ci				break;
375962306a36Sopenharmony_ci			case (6):
376062306a36Sopenharmony_ci				l1_event(dch->l1, INFO2);
376162306a36Sopenharmony_ci				break;
376262306a36Sopenharmony_ci			case (7):
376362306a36Sopenharmony_ci				l1_event(dch->l1, INFO4_P8);
376462306a36Sopenharmony_ci				break;
376562306a36Sopenharmony_ci			}
376662306a36Sopenharmony_ci		} else {
376762306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_STATE)
376862306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: S/T NT newstate %x\n",
376962306a36Sopenharmony_ci				       __func__, dch->state);
377062306a36Sopenharmony_ci			switch (dch->state) {
377162306a36Sopenharmony_ci			case (2):
377262306a36Sopenharmony_ci				if (hc->chan[ch].nt_timer == 0) {
377362306a36Sopenharmony_ci					hc->chan[ch].nt_timer = -1;
377462306a36Sopenharmony_ci					HFC_outb(hc, R_ST_SEL,
377562306a36Sopenharmony_ci						 hc->chan[ch].port);
377662306a36Sopenharmony_ci					/* undocumented: delay after R_ST_SEL */
377762306a36Sopenharmony_ci					udelay(1);
377862306a36Sopenharmony_ci					HFC_outb(hc, A_ST_WR_STATE, 4 |
377962306a36Sopenharmony_ci						 V_ST_LD_STA); /* G4 */
378062306a36Sopenharmony_ci					udelay(6); /* wait at least 5,21us */
378162306a36Sopenharmony_ci					HFC_outb(hc, A_ST_WR_STATE, 4);
378262306a36Sopenharmony_ci					dch->state = 4;
378362306a36Sopenharmony_ci				} else {
378462306a36Sopenharmony_ci					/* one extra count for the next event */
378562306a36Sopenharmony_ci					hc->chan[ch].nt_timer =
378662306a36Sopenharmony_ci						nt_t1_count[poll_timer] + 1;
378762306a36Sopenharmony_ci					HFC_outb(hc, R_ST_SEL,
378862306a36Sopenharmony_ci						 hc->chan[ch].port);
378962306a36Sopenharmony_ci					/* undocumented: delay after R_ST_SEL */
379062306a36Sopenharmony_ci					udelay(1);
379162306a36Sopenharmony_ci					/* allow G2 -> G3 transition */
379262306a36Sopenharmony_ci					HFC_outb(hc, A_ST_WR_STATE, 2 |
379362306a36Sopenharmony_ci						 V_SET_G2_G3);
379462306a36Sopenharmony_ci				}
379562306a36Sopenharmony_ci				break;
379662306a36Sopenharmony_ci			case (1):
379762306a36Sopenharmony_ci				hc->chan[ch].nt_timer = -1;
379862306a36Sopenharmony_ci				test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
379962306a36Sopenharmony_ci				_queue_data(&dch->dev.D, PH_DEACTIVATE_IND,
380062306a36Sopenharmony_ci					    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
380162306a36Sopenharmony_ci				break;
380262306a36Sopenharmony_ci			case (4):
380362306a36Sopenharmony_ci				hc->chan[ch].nt_timer = -1;
380462306a36Sopenharmony_ci				break;
380562306a36Sopenharmony_ci			case (3):
380662306a36Sopenharmony_ci				hc->chan[ch].nt_timer = -1;
380762306a36Sopenharmony_ci				test_and_set_bit(FLG_ACTIVE, &dch->Flags);
380862306a36Sopenharmony_ci				_queue_data(&dch->dev.D, PH_ACTIVATE_IND,
380962306a36Sopenharmony_ci					    MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
381062306a36Sopenharmony_ci				break;
381162306a36Sopenharmony_ci			}
381262306a36Sopenharmony_ci		}
381362306a36Sopenharmony_ci	}
381462306a36Sopenharmony_ci}
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci/*
381762306a36Sopenharmony_ci * called for card mode init message
381862306a36Sopenharmony_ci */
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_cistatic void
382162306a36Sopenharmony_cihfcmulti_initmode(struct dchannel *dch)
382262306a36Sopenharmony_ci{
382362306a36Sopenharmony_ci	struct hfc_multi *hc = dch->hw;
382462306a36Sopenharmony_ci	u_char		a_st_wr_state, r_e1_wr_sta;
382562306a36Sopenharmony_ci	int		i, pt;
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
382862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: entered\n", __func__);
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci	i = dch->slot;
383162306a36Sopenharmony_ci	pt = hc->chan[i].port;
383262306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1) {
383362306a36Sopenharmony_ci		/* E1 */
383462306a36Sopenharmony_ci		hc->chan[hc->dnum[pt]].slot_tx = -1;
383562306a36Sopenharmony_ci		hc->chan[hc->dnum[pt]].slot_rx = -1;
383662306a36Sopenharmony_ci		hc->chan[hc->dnum[pt]].conf = -1;
383762306a36Sopenharmony_ci		if (hc->dnum[pt]) {
383862306a36Sopenharmony_ci			mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol,
383962306a36Sopenharmony_ci				      -1, 0, -1, 0);
384062306a36Sopenharmony_ci			timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0);
384162306a36Sopenharmony_ci		}
384262306a36Sopenharmony_ci		for (i = 1; i <= 31; i++) {
384362306a36Sopenharmony_ci			if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
384462306a36Sopenharmony_ci				continue;
384562306a36Sopenharmony_ci			hc->chan[i].slot_tx = -1;
384662306a36Sopenharmony_ci			hc->chan[i].slot_rx = -1;
384762306a36Sopenharmony_ci			hc->chan[i].conf = -1;
384862306a36Sopenharmony_ci			mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0);
384962306a36Sopenharmony_ci		}
385062306a36Sopenharmony_ci	}
385162306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1 && pt == 0) {
385262306a36Sopenharmony_ci		/* E1, port 0 */
385362306a36Sopenharmony_ci		dch = hc->chan[hc->dnum[0]].dch;
385462306a36Sopenharmony_ci		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
385562306a36Sopenharmony_ci			HFC_outb(hc, R_LOS0, 255); /* 2 ms */
385662306a36Sopenharmony_ci			HFC_outb(hc, R_LOS1, 255); /* 512 ms */
385762306a36Sopenharmony_ci		}
385862306a36Sopenharmony_ci		if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) {
385962306a36Sopenharmony_ci			HFC_outb(hc, R_RX0, 0);
386062306a36Sopenharmony_ci			hc->hw.r_tx0 = 0 | V_OUT_EN;
386162306a36Sopenharmony_ci		} else {
386262306a36Sopenharmony_ci			HFC_outb(hc, R_RX0, 1);
386362306a36Sopenharmony_ci			hc->hw.r_tx0 = 1 | V_OUT_EN;
386462306a36Sopenharmony_ci		}
386562306a36Sopenharmony_ci		hc->hw.r_tx1 = V_ATX | V_NTRI;
386662306a36Sopenharmony_ci		HFC_outb(hc, R_TX0, hc->hw.r_tx0);
386762306a36Sopenharmony_ci		HFC_outb(hc, R_TX1, hc->hw.r_tx1);
386862306a36Sopenharmony_ci		HFC_outb(hc, R_TX_FR0, 0x00);
386962306a36Sopenharmony_ci		HFC_outb(hc, R_TX_FR1, 0xf8);
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
387262306a36Sopenharmony_ci			HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci		HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
387762306a36Sopenharmony_ci			HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci		if (dch->dev.D.protocol == ISDN_P_NT_E1) {
388062306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
388162306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: E1 port is NT-mode\n",
388262306a36Sopenharmony_ci				       __func__);
388362306a36Sopenharmony_ci			r_e1_wr_sta = 0; /* G0 */
388462306a36Sopenharmony_ci			hc->e1_getclock = 0;
388562306a36Sopenharmony_ci		} else {
388662306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
388762306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: E1 port is TE-mode\n",
388862306a36Sopenharmony_ci				       __func__);
388962306a36Sopenharmony_ci			r_e1_wr_sta = 0; /* F0 */
389062306a36Sopenharmony_ci			hc->e1_getclock = 1;
389162306a36Sopenharmony_ci		}
389262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
389362306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
389462306a36Sopenharmony_ci		else
389562306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_OUT, 0);
389662306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip))
389762306a36Sopenharmony_ci			hc->e1_getclock = 1;
389862306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip))
389962306a36Sopenharmony_ci			hc->e1_getclock = 0;
390062306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
390162306a36Sopenharmony_ci			/* SLAVE (clock master) */
390262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
390362306a36Sopenharmony_ci				printk(KERN_DEBUG
390462306a36Sopenharmony_ci				       "%s: E1 port is clock master "
390562306a36Sopenharmony_ci				       "(clock from PCM)\n", __func__);
390662306a36Sopenharmony_ci			HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC);
390762306a36Sopenharmony_ci		} else {
390862306a36Sopenharmony_ci			if (hc->e1_getclock) {
390962306a36Sopenharmony_ci				/* MASTER (clock slave) */
391062306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_INIT)
391162306a36Sopenharmony_ci					printk(KERN_DEBUG
391262306a36Sopenharmony_ci					       "%s: E1 port is clock slave "
391362306a36Sopenharmony_ci					       "(clock to PCM)\n", __func__);
391462306a36Sopenharmony_ci				HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
391562306a36Sopenharmony_ci			} else {
391662306a36Sopenharmony_ci				/* MASTER (clock master) */
391762306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_INIT)
391862306a36Sopenharmony_ci					printk(KERN_DEBUG "%s: E1 port is "
391962306a36Sopenharmony_ci					       "clock master "
392062306a36Sopenharmony_ci					       "(clock from QUARTZ)\n",
392162306a36Sopenharmony_ci					       __func__);
392262306a36Sopenharmony_ci				HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC |
392362306a36Sopenharmony_ci					 V_PCM_SYNC | V_JATT_OFF);
392462306a36Sopenharmony_ci				HFC_outb(hc, R_SYNC_OUT, 0);
392562306a36Sopenharmony_ci			}
392662306a36Sopenharmony_ci		}
392762306a36Sopenharmony_ci		HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */
392862306a36Sopenharmony_ci		HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
392962306a36Sopenharmony_ci		HFC_outb(hc, R_PWM0, 0x50);
393062306a36Sopenharmony_ci		HFC_outb(hc, R_PWM1, 0xff);
393162306a36Sopenharmony_ci		/* state machine setup */
393262306a36Sopenharmony_ci		HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA);
393362306a36Sopenharmony_ci		udelay(6); /* wait at least 5,21us */
393462306a36Sopenharmony_ci		HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta);
393562306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
393662306a36Sopenharmony_ci			hc->syncronized = 0;
393762306a36Sopenharmony_ci			plxsd_checksync(hc, 0);
393862306a36Sopenharmony_ci		}
393962306a36Sopenharmony_ci	}
394062306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_E1) {
394162306a36Sopenharmony_ci		/* ST */
394262306a36Sopenharmony_ci		hc->chan[i].slot_tx = -1;
394362306a36Sopenharmony_ci		hc->chan[i].slot_rx = -1;
394462306a36Sopenharmony_ci		hc->chan[i].conf = -1;
394562306a36Sopenharmony_ci		mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0);
394662306a36Sopenharmony_ci		timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0);
394762306a36Sopenharmony_ci		hc->chan[i - 2].slot_tx = -1;
394862306a36Sopenharmony_ci		hc->chan[i - 2].slot_rx = -1;
394962306a36Sopenharmony_ci		hc->chan[i - 2].conf = -1;
395062306a36Sopenharmony_ci		mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0);
395162306a36Sopenharmony_ci		hc->chan[i - 1].slot_tx = -1;
395262306a36Sopenharmony_ci		hc->chan[i - 1].slot_rx = -1;
395362306a36Sopenharmony_ci		hc->chan[i - 1].conf = -1;
395462306a36Sopenharmony_ci		mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
395562306a36Sopenharmony_ci		/* select interface */
395662306a36Sopenharmony_ci		HFC_outb(hc, R_ST_SEL, pt);
395762306a36Sopenharmony_ci		/* undocumented: delay after R_ST_SEL */
395862306a36Sopenharmony_ci		udelay(1);
395962306a36Sopenharmony_ci		if (dch->dev.D.protocol == ISDN_P_NT_S0) {
396062306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
396162306a36Sopenharmony_ci				printk(KERN_DEBUG
396262306a36Sopenharmony_ci				       "%s: ST port %d is NT-mode\n",
396362306a36Sopenharmony_ci				       __func__, pt);
396462306a36Sopenharmony_ci			/* clock delay */
396562306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt);
396662306a36Sopenharmony_ci			a_st_wr_state = 1; /* G1 */
396762306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[pt] = V_ST_MD;
396862306a36Sopenharmony_ci		} else {
396962306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
397062306a36Sopenharmony_ci				printk(KERN_DEBUG
397162306a36Sopenharmony_ci				       "%s: ST port %d is TE-mode\n",
397262306a36Sopenharmony_ci				       __func__, pt);
397362306a36Sopenharmony_ci			/* clock delay */
397462306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te);
397562306a36Sopenharmony_ci			a_st_wr_state = 2; /* F2 */
397662306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[pt] = 0;
397762306a36Sopenharmony_ci		}
397862306a36Sopenharmony_ci		if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg))
397962306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[pt] |= V_TX_LI;
398062306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_XHFC) {
398162306a36Sopenharmony_ci			hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */;
398262306a36Sopenharmony_ci			HFC_outb(hc, 0x35 /* A_ST_CTRL3 */,
398362306a36Sopenharmony_ci				 0x7c << 1 /* V_ST_PULSE */);
398462306a36Sopenharmony_ci		}
398562306a36Sopenharmony_ci		/* line setup */
398662306a36Sopenharmony_ci		HFC_outb(hc, A_ST_CTRL0,  hc->hw.a_st_ctrl0[pt]);
398762306a36Sopenharmony_ci		/* disable E-channel */
398862306a36Sopenharmony_ci		if ((dch->dev.D.protocol == ISDN_P_NT_S0) ||
398962306a36Sopenharmony_ci		    test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg))
399062306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CTRL1, V_E_IGNO);
399162306a36Sopenharmony_ci		else
399262306a36Sopenharmony_ci			HFC_outb(hc, A_ST_CTRL1, 0);
399362306a36Sopenharmony_ci		/* enable B-channel receive */
399462306a36Sopenharmony_ci		HFC_outb(hc, A_ST_CTRL2,  V_B1_RX_EN | V_B2_RX_EN);
399562306a36Sopenharmony_ci		/* state machine setup */
399662306a36Sopenharmony_ci		HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA);
399762306a36Sopenharmony_ci		udelay(6); /* wait at least 5,21us */
399862306a36Sopenharmony_ci		HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state);
399962306a36Sopenharmony_ci		hc->hw.r_sci_msk |= 1 << pt;
400062306a36Sopenharmony_ci		/* state machine interrupts */
400162306a36Sopenharmony_ci		HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk);
400262306a36Sopenharmony_ci		/* unset sync on port */
400362306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
400462306a36Sopenharmony_ci			hc->syncronized &=
400562306a36Sopenharmony_ci				~(1 << hc->chan[dch->slot].port);
400662306a36Sopenharmony_ci			plxsd_checksync(hc, 0);
400762306a36Sopenharmony_ci		}
400862306a36Sopenharmony_ci	}
400962306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
401062306a36Sopenharmony_ci		printk("%s: done\n", __func__);
401162306a36Sopenharmony_ci}
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_cistatic int
401562306a36Sopenharmony_ciopen_dchannel(struct hfc_multi *hc, struct dchannel *dch,
401662306a36Sopenharmony_ci	      struct channel_req *rq)
401762306a36Sopenharmony_ci{
401862306a36Sopenharmony_ci	int	err = 0;
401962306a36Sopenharmony_ci	u_long	flags;
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	if (debug & DEBUG_HW_OPEN)
402262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
402362306a36Sopenharmony_ci		       dch->dev.id, __builtin_return_address(0));
402462306a36Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
402562306a36Sopenharmony_ci		return -EINVAL;
402662306a36Sopenharmony_ci	if ((dch->dev.D.protocol != ISDN_P_NONE) &&
402762306a36Sopenharmony_ci	    (dch->dev.D.protocol != rq->protocol)) {
402862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MODE)
402962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: change protocol %x to %x\n",
403062306a36Sopenharmony_ci			       __func__, dch->dev.D.protocol, rq->protocol);
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci	if ((dch->dev.D.protocol == ISDN_P_TE_S0) &&
403362306a36Sopenharmony_ci	    (rq->protocol != ISDN_P_TE_S0))
403462306a36Sopenharmony_ci		l1_event(dch->l1, CLOSE_CHANNEL);
403562306a36Sopenharmony_ci	if (dch->dev.D.protocol != rq->protocol) {
403662306a36Sopenharmony_ci		if (rq->protocol == ISDN_P_TE_S0) {
403762306a36Sopenharmony_ci			err = create_l1(dch, hfcm_l1callback);
403862306a36Sopenharmony_ci			if (err)
403962306a36Sopenharmony_ci				return err;
404062306a36Sopenharmony_ci		}
404162306a36Sopenharmony_ci		dch->dev.D.protocol = rq->protocol;
404262306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
404362306a36Sopenharmony_ci		hfcmulti_initmode(dch);
404462306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
404562306a36Sopenharmony_ci	}
404662306a36Sopenharmony_ci	if (test_bit(FLG_ACTIVE, &dch->Flags))
404762306a36Sopenharmony_ci		_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
404862306a36Sopenharmony_ci			    0, NULL, GFP_KERNEL);
404962306a36Sopenharmony_ci	rq->ch = &dch->dev.D;
405062306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
405162306a36Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
405262306a36Sopenharmony_ci	return 0;
405362306a36Sopenharmony_ci}
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_cistatic int
405662306a36Sopenharmony_ciopen_bchannel(struct hfc_multi *hc, struct dchannel *dch,
405762306a36Sopenharmony_ci	      struct channel_req *rq)
405862306a36Sopenharmony_ci{
405962306a36Sopenharmony_ci	struct bchannel	*bch;
406062306a36Sopenharmony_ci	int		ch;
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	if (!test_channelmap(rq->adr.channel, dch->dev.channelmap))
406362306a36Sopenharmony_ci		return -EINVAL;
406462306a36Sopenharmony_ci	if (rq->protocol == ISDN_P_NONE)
406562306a36Sopenharmony_ci		return -EINVAL;
406662306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1)
406762306a36Sopenharmony_ci		ch = rq->adr.channel;
406862306a36Sopenharmony_ci	else
406962306a36Sopenharmony_ci		ch = (rq->adr.channel - 1) + (dch->slot - 2);
407062306a36Sopenharmony_ci	bch = hc->chan[ch].bch;
407162306a36Sopenharmony_ci	if (!bch) {
407262306a36Sopenharmony_ci		printk(KERN_ERR "%s:internal error ch %d has no bch\n",
407362306a36Sopenharmony_ci		       __func__, ch);
407462306a36Sopenharmony_ci		return -EINVAL;
407562306a36Sopenharmony_ci	}
407662306a36Sopenharmony_ci	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
407762306a36Sopenharmony_ci		return -EBUSY; /* b-channel can be only open once */
407862306a36Sopenharmony_ci	bch->ch.protocol = rq->protocol;
407962306a36Sopenharmony_ci	hc->chan[ch].rx_off = 0;
408062306a36Sopenharmony_ci	rq->ch = &bch->ch;
408162306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
408262306a36Sopenharmony_ci		printk(KERN_WARNING "%s:cannot get module\n", __func__);
408362306a36Sopenharmony_ci	return 0;
408462306a36Sopenharmony_ci}
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci/*
408762306a36Sopenharmony_ci * device control function
408862306a36Sopenharmony_ci */
408962306a36Sopenharmony_cistatic int
409062306a36Sopenharmony_cichannel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
409162306a36Sopenharmony_ci{
409262306a36Sopenharmony_ci	struct hfc_multi	*hc = dch->hw;
409362306a36Sopenharmony_ci	int	ret = 0;
409462306a36Sopenharmony_ci	int	wd_mode, wd_cnt;
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_ci	switch (cq->op) {
409762306a36Sopenharmony_ci	case MISDN_CTRL_GETOP:
409862306a36Sopenharmony_ci		cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3;
409962306a36Sopenharmony_ci		break;
410062306a36Sopenharmony_ci	case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
410162306a36Sopenharmony_ci		wd_cnt = cq->p1 & 0xf;
410262306a36Sopenharmony_ci		wd_mode = !!(cq->p1 >> 4);
410362306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
410462306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s"
410562306a36Sopenharmony_ci			       ", counter 0x%x\n", __func__,
410662306a36Sopenharmony_ci			       wd_mode ? "AUTO" : "MANUAL", wd_cnt);
410762306a36Sopenharmony_ci		/* set the watchdog timer */
410862306a36Sopenharmony_ci		HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4));
410962306a36Sopenharmony_ci		hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0);
411062306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_XHFC)
411162306a36Sopenharmony_ci			hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */;
411262306a36Sopenharmony_ci		/* init the watchdog register and reset the counter */
411362306a36Sopenharmony_ci		HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
411462306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
411562306a36Sopenharmony_ci			/* enable the watchdog output for Speech-Design */
411662306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_SEL,  V_GPIO_SEL7);
411762306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_EN1,  V_GPIO_EN15);
411862306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_OUT1, 0);
411962306a36Sopenharmony_ci			HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15);
412062306a36Sopenharmony_ci		}
412162306a36Sopenharmony_ci		break;
412262306a36Sopenharmony_ci	case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */
412362306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_MSG)
412462306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n",
412562306a36Sopenharmony_ci			       __func__);
412662306a36Sopenharmony_ci		HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
412762306a36Sopenharmony_ci		break;
412862306a36Sopenharmony_ci	case MISDN_CTRL_L1_TIMER3:
412962306a36Sopenharmony_ci		ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
413062306a36Sopenharmony_ci		break;
413162306a36Sopenharmony_ci	default:
413262306a36Sopenharmony_ci		printk(KERN_WARNING "%s: unknown Op %x\n",
413362306a36Sopenharmony_ci		       __func__, cq->op);
413462306a36Sopenharmony_ci		ret = -EINVAL;
413562306a36Sopenharmony_ci		break;
413662306a36Sopenharmony_ci	}
413762306a36Sopenharmony_ci	return ret;
413862306a36Sopenharmony_ci}
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_cistatic int
414162306a36Sopenharmony_cihfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
414262306a36Sopenharmony_ci{
414362306a36Sopenharmony_ci	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
414462306a36Sopenharmony_ci	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
414562306a36Sopenharmony_ci	struct hfc_multi	*hc = dch->hw;
414662306a36Sopenharmony_ci	struct channel_req	*rq;
414762306a36Sopenharmony_ci	int			err = 0;
414862306a36Sopenharmony_ci	u_long			flags;
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	if (dch->debug & DEBUG_HW)
415162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: cmd:%x %p\n",
415262306a36Sopenharmony_ci		       __func__, cmd, arg);
415362306a36Sopenharmony_ci	switch (cmd) {
415462306a36Sopenharmony_ci	case OPEN_CHANNEL:
415562306a36Sopenharmony_ci		rq = arg;
415662306a36Sopenharmony_ci		switch (rq->protocol) {
415762306a36Sopenharmony_ci		case ISDN_P_TE_S0:
415862306a36Sopenharmony_ci		case ISDN_P_NT_S0:
415962306a36Sopenharmony_ci			if (hc->ctype == HFC_TYPE_E1) {
416062306a36Sopenharmony_ci				err = -EINVAL;
416162306a36Sopenharmony_ci				break;
416262306a36Sopenharmony_ci			}
416362306a36Sopenharmony_ci			err = open_dchannel(hc, dch, rq); /* locked there */
416462306a36Sopenharmony_ci			break;
416562306a36Sopenharmony_ci		case ISDN_P_TE_E1:
416662306a36Sopenharmony_ci		case ISDN_P_NT_E1:
416762306a36Sopenharmony_ci			if (hc->ctype != HFC_TYPE_E1) {
416862306a36Sopenharmony_ci				err = -EINVAL;
416962306a36Sopenharmony_ci				break;
417062306a36Sopenharmony_ci			}
417162306a36Sopenharmony_ci			err = open_dchannel(hc, dch, rq); /* locked there */
417262306a36Sopenharmony_ci			break;
417362306a36Sopenharmony_ci		default:
417462306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
417562306a36Sopenharmony_ci			err = open_bchannel(hc, dch, rq);
417662306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
417762306a36Sopenharmony_ci		}
417862306a36Sopenharmony_ci		break;
417962306a36Sopenharmony_ci	case CLOSE_CHANNEL:
418062306a36Sopenharmony_ci		if (debug & DEBUG_HW_OPEN)
418162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
418262306a36Sopenharmony_ci			       __func__, dch->dev.id,
418362306a36Sopenharmony_ci			       __builtin_return_address(0));
418462306a36Sopenharmony_ci		module_put(THIS_MODULE);
418562306a36Sopenharmony_ci		break;
418662306a36Sopenharmony_ci	case CONTROL_CHANNEL:
418762306a36Sopenharmony_ci		spin_lock_irqsave(&hc->lock, flags);
418862306a36Sopenharmony_ci		err = channel_dctrl(dch, arg);
418962306a36Sopenharmony_ci		spin_unlock_irqrestore(&hc->lock, flags);
419062306a36Sopenharmony_ci		break;
419162306a36Sopenharmony_ci	default:
419262306a36Sopenharmony_ci		if (dch->debug & DEBUG_HW)
419362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: unknown command %x\n",
419462306a36Sopenharmony_ci			       __func__, cmd);
419562306a36Sopenharmony_ci		err = -EINVAL;
419662306a36Sopenharmony_ci	}
419762306a36Sopenharmony_ci	return err;
419862306a36Sopenharmony_ci}
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_cistatic int
420162306a36Sopenharmony_ciclockctl(void *priv, int enable)
420262306a36Sopenharmony_ci{
420362306a36Sopenharmony_ci	struct hfc_multi *hc = priv;
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_ci	hc->iclock_on = enable;
420662306a36Sopenharmony_ci	return 0;
420762306a36Sopenharmony_ci}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci/*
421062306a36Sopenharmony_ci * initialize the card
421162306a36Sopenharmony_ci */
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci/*
421462306a36Sopenharmony_ci * start timer irq, wait some time and check if we have interrupts.
421562306a36Sopenharmony_ci * if not, reset chip and try again.
421662306a36Sopenharmony_ci */
421762306a36Sopenharmony_cistatic int
421862306a36Sopenharmony_ciinit_card(struct hfc_multi *hc)
421962306a36Sopenharmony_ci{
422062306a36Sopenharmony_ci	int	err = -EIO;
422162306a36Sopenharmony_ci	u_long	flags;
422262306a36Sopenharmony_ci	void	__iomem *plx_acc;
422362306a36Sopenharmony_ci	u_long	plx_flags;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
422662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: entered\n", __func__);
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
422962306a36Sopenharmony_ci	/* set interrupts but leave global interrupt disabled */
423062306a36Sopenharmony_ci	hc->hw.r_irq_ctrl = V_FIFO_IRQ;
423162306a36Sopenharmony_ci	disable_hwirq(hc);
423262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci	if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED,
423562306a36Sopenharmony_ci			"HFC-multi", hc)) {
423662306a36Sopenharmony_ci		printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n",
423762306a36Sopenharmony_ci		       hc->irq);
423862306a36Sopenharmony_ci		hc->irq = 0;
423962306a36Sopenharmony_ci		return -EIO;
424062306a36Sopenharmony_ci	}
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
424362306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
424462306a36Sopenharmony_ci		plx_acc = hc->plx_membase + PLX_INTCSR;
424562306a36Sopenharmony_ci		writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE),
424662306a36Sopenharmony_ci		       plx_acc); /* enable PCI & LINT1 irq */
424762306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
424862306a36Sopenharmony_ci	}
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
425162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: IRQ %d count %d\n",
425262306a36Sopenharmony_ci		       __func__, hc->irq, hc->irqcnt);
425362306a36Sopenharmony_ci	err = init_chip(hc);
425462306a36Sopenharmony_ci	if (err)
425562306a36Sopenharmony_ci		goto error;
425662306a36Sopenharmony_ci	/*
425762306a36Sopenharmony_ci	 * Finally enable IRQ output
425862306a36Sopenharmony_ci	 * this is only allowed, if an IRQ routine is already
425962306a36Sopenharmony_ci	 * established for this HFC, so don't do that earlier
426062306a36Sopenharmony_ci	 */
426162306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
426262306a36Sopenharmony_ci	enable_hwirq(hc);
426362306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
426462306a36Sopenharmony_ci	/* printk(KERN_DEBUG "no master irq set!!!\n"); */
426562306a36Sopenharmony_ci	set_current_state(TASK_UNINTERRUPTIBLE);
426662306a36Sopenharmony_ci	schedule_timeout((100 * HZ) / 1000); /* Timeout 100ms */
426762306a36Sopenharmony_ci	/* turn IRQ off until chip is completely initialized */
426862306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
426962306a36Sopenharmony_ci	disable_hwirq(hc);
427062306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
427162306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
427262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: IRQ %d count %d\n",
427362306a36Sopenharmony_ci		       __func__, hc->irq, hc->irqcnt);
427462306a36Sopenharmony_ci	if (hc->irqcnt) {
427562306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
427662306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: done\n", __func__);
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_ci		return 0;
427962306a36Sopenharmony_ci	}
428062306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
428162306a36Sopenharmony_ci		printk(KERN_INFO "ignoring missing interrupts\n");
428262306a36Sopenharmony_ci		return 0;
428362306a36Sopenharmony_ci	}
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	printk(KERN_ERR "HFC PCI: IRQ(%d) getting no interrupts during init.\n",
428662306a36Sopenharmony_ci	       hc->irq);
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	err = -EIO;
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_cierror:
429162306a36Sopenharmony_ci	if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
429262306a36Sopenharmony_ci		spin_lock_irqsave(&plx_lock, plx_flags);
429362306a36Sopenharmony_ci		plx_acc = hc->plx_membase + PLX_INTCSR;
429462306a36Sopenharmony_ci		writew(0x00, plx_acc); /*disable IRQs*/
429562306a36Sopenharmony_ci		spin_unlock_irqrestore(&plx_lock, plx_flags);
429662306a36Sopenharmony_ci	}
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
429962306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: free irq %d\n", __func__, hc->irq);
430062306a36Sopenharmony_ci	if (hc->irq) {
430162306a36Sopenharmony_ci		free_irq(hc->irq, hc);
430262306a36Sopenharmony_ci		hc->irq = 0;
430362306a36Sopenharmony_ci	}
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
430662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: done (err=%d)\n", __func__, err);
430762306a36Sopenharmony_ci	return err;
430862306a36Sopenharmony_ci}
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci/*
431162306a36Sopenharmony_ci * find pci device and set it up
431262306a36Sopenharmony_ci */
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_cistatic int
431562306a36Sopenharmony_cisetup_pci(struct hfc_multi *hc, struct pci_dev *pdev,
431662306a36Sopenharmony_ci	  const struct pci_device_id *ent)
431762306a36Sopenharmony_ci{
431862306a36Sopenharmony_ci	struct hm_map	*m = (struct hm_map *)ent->driver_data;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	printk(KERN_INFO
432162306a36Sopenharmony_ci	       "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n",
432262306a36Sopenharmony_ci	       m->vendor_name, m->card_name, m->clock2 ? "double" : "normal");
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	hc->pci_dev = pdev;
432562306a36Sopenharmony_ci	if (m->clock2)
432662306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip);
432762306a36Sopenharmony_ci
432862306a36Sopenharmony_ci	if (ent->vendor == PCI_VENDOR_ID_DIGIUM &&
432962306a36Sopenharmony_ci	    ent->device == PCI_DEVICE_ID_DIGIUM_HFC4S) {
433062306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_B410P, &hc->chip);
433162306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip);
433262306a36Sopenharmony_ci		test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
433362306a36Sopenharmony_ci		hc->slots = 32;
433462306a36Sopenharmony_ci	}
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	if (hc->pci_dev->irq <= 0) {
433762306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n");
433862306a36Sopenharmony_ci		return -EIO;
433962306a36Sopenharmony_ci	}
434062306a36Sopenharmony_ci	if (pci_enable_device(hc->pci_dev)) {
434162306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n");
434262306a36Sopenharmony_ci		return -EIO;
434362306a36Sopenharmony_ci	}
434462306a36Sopenharmony_ci	hc->leds = m->leds;
434562306a36Sopenharmony_ci	hc->ledstate = 0xAFFEAFFE;
434662306a36Sopenharmony_ci	hc->opticalsupport = m->opticalsupport;
434762306a36Sopenharmony_ci
434862306a36Sopenharmony_ci	hc->pci_iobase = 0;
434962306a36Sopenharmony_ci	hc->pci_membase = NULL;
435062306a36Sopenharmony_ci	hc->plx_membase = NULL;
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	/* set memory access methods */
435362306a36Sopenharmony_ci	if (m->io_mode) /* use mode from card config */
435462306a36Sopenharmony_ci		hc->io_mode = m->io_mode;
435562306a36Sopenharmony_ci	switch (hc->io_mode) {
435662306a36Sopenharmony_ci	case HFC_IO_MODE_PLXSD:
435762306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_PLXSD, &hc->chip);
435862306a36Sopenharmony_ci		hc->slots = 128; /* required */
435962306a36Sopenharmony_ci		hc->HFC_outb = HFC_outb_pcimem;
436062306a36Sopenharmony_ci		hc->HFC_inb = HFC_inb_pcimem;
436162306a36Sopenharmony_ci		hc->HFC_inw = HFC_inw_pcimem;
436262306a36Sopenharmony_ci		hc->HFC_wait = HFC_wait_pcimem;
436362306a36Sopenharmony_ci		hc->read_fifo = read_fifo_pcimem;
436462306a36Sopenharmony_ci		hc->write_fifo = write_fifo_pcimem;
436562306a36Sopenharmony_ci		hc->plx_origmembase =  hc->pci_dev->resource[0].start;
436662306a36Sopenharmony_ci		/* MEMBASE 1 is PLX PCI Bridge */
436762306a36Sopenharmony_ci
436862306a36Sopenharmony_ci		if (!hc->plx_origmembase) {
436962306a36Sopenharmony_ci			printk(KERN_WARNING
437062306a36Sopenharmony_ci			       "HFC-multi: No IO-Memory for PCI PLX bridge found\n");
437162306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
437262306a36Sopenharmony_ci			return -EIO;
437362306a36Sopenharmony_ci		}
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci		hc->plx_membase = ioremap(hc->plx_origmembase, 0x80);
437662306a36Sopenharmony_ci		if (!hc->plx_membase) {
437762306a36Sopenharmony_ci			printk(KERN_WARNING
437862306a36Sopenharmony_ci			       "HFC-multi: failed to remap plx address space. "
437962306a36Sopenharmony_ci			       "(internal error)\n");
438062306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
438162306a36Sopenharmony_ci			return -EIO;
438262306a36Sopenharmony_ci		}
438362306a36Sopenharmony_ci		printk(KERN_INFO
438462306a36Sopenharmony_ci		       "HFC-multi: plx_membase:%#lx plx_origmembase:%#lx\n",
438562306a36Sopenharmony_ci		       (u_long)hc->plx_membase, hc->plx_origmembase);
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_ci		hc->pci_origmembase =  hc->pci_dev->resource[2].start;
438862306a36Sopenharmony_ci		/* MEMBASE 1 is PLX PCI Bridge */
438962306a36Sopenharmony_ci		if (!hc->pci_origmembase) {
439062306a36Sopenharmony_ci			printk(KERN_WARNING
439162306a36Sopenharmony_ci			       "HFC-multi: No IO-Memory for PCI card found\n");
439262306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
439362306a36Sopenharmony_ci			return -EIO;
439462306a36Sopenharmony_ci		}
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci		hc->pci_membase = ioremap(hc->pci_origmembase, 0x400);
439762306a36Sopenharmony_ci		if (!hc->pci_membase) {
439862306a36Sopenharmony_ci			printk(KERN_WARNING "HFC-multi: failed to remap io "
439962306a36Sopenharmony_ci			       "address space. (internal error)\n");
440062306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
440162306a36Sopenharmony_ci			return -EIO;
440262306a36Sopenharmony_ci		}
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci		printk(KERN_INFO
440562306a36Sopenharmony_ci		       "card %d: defined at MEMBASE %#lx (%#lx) IRQ %d HZ %d "
440662306a36Sopenharmony_ci		       "leds-type %d\n",
440762306a36Sopenharmony_ci		       hc->id, (u_long)hc->pci_membase, hc->pci_origmembase,
440862306a36Sopenharmony_ci		       hc->pci_dev->irq, HZ, hc->leds);
440962306a36Sopenharmony_ci		pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
441062306a36Sopenharmony_ci		break;
441162306a36Sopenharmony_ci	case HFC_IO_MODE_PCIMEM:
441262306a36Sopenharmony_ci		hc->HFC_outb = HFC_outb_pcimem;
441362306a36Sopenharmony_ci		hc->HFC_inb = HFC_inb_pcimem;
441462306a36Sopenharmony_ci		hc->HFC_inw = HFC_inw_pcimem;
441562306a36Sopenharmony_ci		hc->HFC_wait = HFC_wait_pcimem;
441662306a36Sopenharmony_ci		hc->read_fifo = read_fifo_pcimem;
441762306a36Sopenharmony_ci		hc->write_fifo = write_fifo_pcimem;
441862306a36Sopenharmony_ci		hc->pci_origmembase = hc->pci_dev->resource[1].start;
441962306a36Sopenharmony_ci		if (!hc->pci_origmembase) {
442062306a36Sopenharmony_ci			printk(KERN_WARNING
442162306a36Sopenharmony_ci			       "HFC-multi: No IO-Memory for PCI card found\n");
442262306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
442362306a36Sopenharmony_ci			return -EIO;
442462306a36Sopenharmony_ci		}
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci		hc->pci_membase = ioremap(hc->pci_origmembase, 256);
442762306a36Sopenharmony_ci		if (!hc->pci_membase) {
442862306a36Sopenharmony_ci			printk(KERN_WARNING
442962306a36Sopenharmony_ci			       "HFC-multi: failed to remap io address space. "
443062306a36Sopenharmony_ci			       "(internal error)\n");
443162306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
443262306a36Sopenharmony_ci			return -EIO;
443362306a36Sopenharmony_ci		}
443462306a36Sopenharmony_ci		printk(KERN_INFO "card %d: defined at MEMBASE %#lx (%#lx) IRQ "
443562306a36Sopenharmony_ci		       "%d HZ %d leds-type %d\n", hc->id, (u_long)hc->pci_membase,
443662306a36Sopenharmony_ci		       hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds);
443762306a36Sopenharmony_ci		pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO);
443862306a36Sopenharmony_ci		break;
443962306a36Sopenharmony_ci	case HFC_IO_MODE_REGIO:
444062306a36Sopenharmony_ci		hc->HFC_outb = HFC_outb_regio;
444162306a36Sopenharmony_ci		hc->HFC_inb = HFC_inb_regio;
444262306a36Sopenharmony_ci		hc->HFC_inw = HFC_inw_regio;
444362306a36Sopenharmony_ci		hc->HFC_wait = HFC_wait_regio;
444462306a36Sopenharmony_ci		hc->read_fifo = read_fifo_regio;
444562306a36Sopenharmony_ci		hc->write_fifo = write_fifo_regio;
444662306a36Sopenharmony_ci		hc->pci_iobase = (u_int) hc->pci_dev->resource[0].start;
444762306a36Sopenharmony_ci		if (!hc->pci_iobase) {
444862306a36Sopenharmony_ci			printk(KERN_WARNING
444962306a36Sopenharmony_ci			       "HFC-multi: No IO for PCI card found\n");
445062306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
445162306a36Sopenharmony_ci			return -EIO;
445262306a36Sopenharmony_ci		}
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci		if (!request_region(hc->pci_iobase, 8, "hfcmulti")) {
445562306a36Sopenharmony_ci			printk(KERN_WARNING "HFC-multi: failed to request "
445662306a36Sopenharmony_ci			       "address space at 0x%08lx (internal error)\n",
445762306a36Sopenharmony_ci			       hc->pci_iobase);
445862306a36Sopenharmony_ci			pci_disable_device(hc->pci_dev);
445962306a36Sopenharmony_ci			return -EIO;
446062306a36Sopenharmony_ci		}
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci		printk(KERN_INFO
446362306a36Sopenharmony_ci		       "%s %s: defined at IOBASE %#x IRQ %d HZ %d leds-type %d\n",
446462306a36Sopenharmony_ci		       m->vendor_name, m->card_name, (u_int) hc->pci_iobase,
446562306a36Sopenharmony_ci		       hc->pci_dev->irq, HZ, hc->leds);
446662306a36Sopenharmony_ci		pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO);
446762306a36Sopenharmony_ci		break;
446862306a36Sopenharmony_ci	default:
446962306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-multi: Invalid IO mode.\n");
447062306a36Sopenharmony_ci		pci_disable_device(hc->pci_dev);
447162306a36Sopenharmony_ci		return -EIO;
447262306a36Sopenharmony_ci	}
447362306a36Sopenharmony_ci
447462306a36Sopenharmony_ci	pci_set_drvdata(hc->pci_dev, hc);
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	/* At this point the needed PCI config is done */
447762306a36Sopenharmony_ci	/* fifos are still not enabled */
447862306a36Sopenharmony_ci	return 0;
447962306a36Sopenharmony_ci}
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci
448262306a36Sopenharmony_ci/*
448362306a36Sopenharmony_ci * remove port
448462306a36Sopenharmony_ci */
448562306a36Sopenharmony_ci
448662306a36Sopenharmony_cistatic void
448762306a36Sopenharmony_cirelease_port(struct hfc_multi *hc, struct dchannel *dch)
448862306a36Sopenharmony_ci{
448962306a36Sopenharmony_ci	int	pt, ci, i = 0;
449062306a36Sopenharmony_ci	u_long	flags;
449162306a36Sopenharmony_ci	struct bchannel *pb;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	ci = dch->slot;
449462306a36Sopenharmony_ci	pt = hc->chan[ci].port;
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
449762306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: entered for port %d\n",
449862306a36Sopenharmony_ci		       __func__, pt + 1);
449962306a36Sopenharmony_ci
450062306a36Sopenharmony_ci	if (pt >= hc->ports) {
450162306a36Sopenharmony_ci		printk(KERN_WARNING "%s: ERROR port out of range (%d).\n",
450262306a36Sopenharmony_ci		       __func__, pt + 1);
450362306a36Sopenharmony_ci		return;
450462306a36Sopenharmony_ci	}
450562306a36Sopenharmony_ci
450662306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
450762306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: releasing port=%d\n",
450862306a36Sopenharmony_ci		       __func__, pt + 1);
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	if (dch->dev.D.protocol == ISDN_P_TE_S0)
451162306a36Sopenharmony_ci		l1_event(dch->l1, CLOSE_CHANNEL);
451262306a36Sopenharmony_ci
451362306a36Sopenharmony_ci	hc->chan[ci].dch = NULL;
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	if (hc->created[pt]) {
451662306a36Sopenharmony_ci		hc->created[pt] = 0;
451762306a36Sopenharmony_ci		mISDN_unregister_device(&dch->dev);
451862306a36Sopenharmony_ci	}
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_ci	if (dch->timer.function) {
452362306a36Sopenharmony_ci		del_timer(&dch->timer);
452462306a36Sopenharmony_ci		dch->timer.function = NULL;
452562306a36Sopenharmony_ci	}
452662306a36Sopenharmony_ci
452762306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1) { /* E1 */
452862306a36Sopenharmony_ci		/* remove sync */
452962306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
453062306a36Sopenharmony_ci			hc->syncronized = 0;
453162306a36Sopenharmony_ci			plxsd_checksync(hc, 1);
453262306a36Sopenharmony_ci		}
453362306a36Sopenharmony_ci		/* free channels */
453462306a36Sopenharmony_ci		for (i = 0; i <= 31; i++) {
453562306a36Sopenharmony_ci			if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
453662306a36Sopenharmony_ci				continue;
453762306a36Sopenharmony_ci			if (hc->chan[i].bch) {
453862306a36Sopenharmony_ci				if (debug & DEBUG_HFCMULTI_INIT)
453962306a36Sopenharmony_ci					printk(KERN_DEBUG
454062306a36Sopenharmony_ci					       "%s: free port %d channel %d\n",
454162306a36Sopenharmony_ci					       __func__, hc->chan[i].port + 1, i);
454262306a36Sopenharmony_ci				pb = hc->chan[i].bch;
454362306a36Sopenharmony_ci				hc->chan[i].bch = NULL;
454462306a36Sopenharmony_ci				spin_unlock_irqrestore(&hc->lock, flags);
454562306a36Sopenharmony_ci				mISDN_freebchannel(pb);
454662306a36Sopenharmony_ci				kfree(pb);
454762306a36Sopenharmony_ci				kfree(hc->chan[i].coeff);
454862306a36Sopenharmony_ci				spin_lock_irqsave(&hc->lock, flags);
454962306a36Sopenharmony_ci			}
455062306a36Sopenharmony_ci		}
455162306a36Sopenharmony_ci	} else {
455262306a36Sopenharmony_ci		/* remove sync */
455362306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
455462306a36Sopenharmony_ci			hc->syncronized &=
455562306a36Sopenharmony_ci				~(1 << hc->chan[ci].port);
455662306a36Sopenharmony_ci			plxsd_checksync(hc, 1);
455762306a36Sopenharmony_ci		}
455862306a36Sopenharmony_ci		/* free channels */
455962306a36Sopenharmony_ci		if (hc->chan[ci - 2].bch) {
456062306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
456162306a36Sopenharmony_ci				printk(KERN_DEBUG
456262306a36Sopenharmony_ci				       "%s: free port %d channel %d\n",
456362306a36Sopenharmony_ci				       __func__, hc->chan[ci - 2].port + 1,
456462306a36Sopenharmony_ci				       ci - 2);
456562306a36Sopenharmony_ci			pb = hc->chan[ci - 2].bch;
456662306a36Sopenharmony_ci			hc->chan[ci - 2].bch = NULL;
456762306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
456862306a36Sopenharmony_ci			mISDN_freebchannel(pb);
456962306a36Sopenharmony_ci			kfree(pb);
457062306a36Sopenharmony_ci			kfree(hc->chan[ci - 2].coeff);
457162306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
457262306a36Sopenharmony_ci		}
457362306a36Sopenharmony_ci		if (hc->chan[ci - 1].bch) {
457462306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
457562306a36Sopenharmony_ci				printk(KERN_DEBUG
457662306a36Sopenharmony_ci				       "%s: free port %d channel %d\n",
457762306a36Sopenharmony_ci				       __func__, hc->chan[ci - 1].port + 1,
457862306a36Sopenharmony_ci				       ci - 1);
457962306a36Sopenharmony_ci			pb = hc->chan[ci - 1].bch;
458062306a36Sopenharmony_ci			hc->chan[ci - 1].bch = NULL;
458162306a36Sopenharmony_ci			spin_unlock_irqrestore(&hc->lock, flags);
458262306a36Sopenharmony_ci			mISDN_freebchannel(pb);
458362306a36Sopenharmony_ci			kfree(pb);
458462306a36Sopenharmony_ci			kfree(hc->chan[ci - 1].coeff);
458562306a36Sopenharmony_ci			spin_lock_irqsave(&hc->lock, flags);
458662306a36Sopenharmony_ci		}
458762306a36Sopenharmony_ci	}
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
459262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__,
459362306a36Sopenharmony_ci			pt+1, ci);
459462306a36Sopenharmony_ci	mISDN_freedchannel(dch);
459562306a36Sopenharmony_ci	kfree(dch);
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
459862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: done!\n", __func__);
459962306a36Sopenharmony_ci}
460062306a36Sopenharmony_ci
460162306a36Sopenharmony_cistatic void
460262306a36Sopenharmony_cirelease_card(struct hfc_multi *hc)
460362306a36Sopenharmony_ci{
460462306a36Sopenharmony_ci	u_long	flags;
460562306a36Sopenharmony_ci	int	ch;
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
460862306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: release card (%d) entered\n",
460962306a36Sopenharmony_ci		       __func__, hc->id);
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_ci	/* unregister clock source */
461262306a36Sopenharmony_ci	if (hc->iclock)
461362306a36Sopenharmony_ci		mISDN_unregister_clock(hc->iclock);
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	/* disable and free irq */
461662306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
461762306a36Sopenharmony_ci	disable_hwirq(hc);
461862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
461962306a36Sopenharmony_ci	udelay(1000);
462062306a36Sopenharmony_ci	if (hc->irq) {
462162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
462262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n",
462362306a36Sopenharmony_ci			    __func__, hc->irq, hc);
462462306a36Sopenharmony_ci		free_irq(hc->irq, hc);
462562306a36Sopenharmony_ci		hc->irq = 0;
462662306a36Sopenharmony_ci
462762306a36Sopenharmony_ci	}
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_ci	/* disable D-channels & B-channels */
463062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
463162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: disable all channels (d and b)\n",
463262306a36Sopenharmony_ci		       __func__);
463362306a36Sopenharmony_ci	for (ch = 0; ch <= 31; ch++) {
463462306a36Sopenharmony_ci		if (hc->chan[ch].dch)
463562306a36Sopenharmony_ci			release_port(hc, hc->chan[ch].dch);
463662306a36Sopenharmony_ci	}
463762306a36Sopenharmony_ci
463862306a36Sopenharmony_ci	/* dimm leds */
463962306a36Sopenharmony_ci	if (hc->leds)
464062306a36Sopenharmony_ci		hfcmulti_leds(hc);
464162306a36Sopenharmony_ci
464262306a36Sopenharmony_ci	/* release hardware */
464362306a36Sopenharmony_ci	release_io_hfcmulti(hc);
464462306a36Sopenharmony_ci
464562306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
464662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: remove instance from list\n",
464762306a36Sopenharmony_ci		       __func__);
464862306a36Sopenharmony_ci	list_del(&hc->list);
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
465162306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: delete instance\n", __func__);
465262306a36Sopenharmony_ci	if (hc == syncmaster)
465362306a36Sopenharmony_ci		syncmaster = NULL;
465462306a36Sopenharmony_ci	kfree(hc);
465562306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
465662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: card successfully removed\n",
465762306a36Sopenharmony_ci		       __func__);
465862306a36Sopenharmony_ci}
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_cistatic void
466162306a36Sopenharmony_ciinit_e1_port_hw(struct hfc_multi *hc, struct hm_map *m)
466262306a36Sopenharmony_ci{
466362306a36Sopenharmony_ci	/* set optical line type */
466462306a36Sopenharmony_ci	if (port[Port_cnt] & 0x001) {
466562306a36Sopenharmony_ci		if (!m->opticalsupport)  {
466662306a36Sopenharmony_ci			printk(KERN_INFO
466762306a36Sopenharmony_ci			       "This board has no optical "
466862306a36Sopenharmony_ci			       "support\n");
466962306a36Sopenharmony_ci		} else {
467062306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
467162306a36Sopenharmony_ci				printk(KERN_DEBUG
467262306a36Sopenharmony_ci				       "%s: PORT set optical "
467362306a36Sopenharmony_ci				       "interfacs: card(%d) "
467462306a36Sopenharmony_ci				       "port(%d)\n",
467562306a36Sopenharmony_ci				       __func__,
467662306a36Sopenharmony_ci				       HFC_cnt + 1, 1);
467762306a36Sopenharmony_ci			test_and_set_bit(HFC_CFG_OPTICAL,
467862306a36Sopenharmony_ci			    &hc->chan[hc->dnum[0]].cfg);
467962306a36Sopenharmony_ci		}
468062306a36Sopenharmony_ci	}
468162306a36Sopenharmony_ci	/* set LOS report */
468262306a36Sopenharmony_ci	if (port[Port_cnt] & 0x004) {
468362306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
468462306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT set "
468562306a36Sopenharmony_ci			       "LOS report: card(%d) port(%d)\n",
468662306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
468762306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_REPORT_LOS,
468862306a36Sopenharmony_ci		    &hc->chan[hc->dnum[0]].cfg);
468962306a36Sopenharmony_ci	}
469062306a36Sopenharmony_ci	/* set AIS report */
469162306a36Sopenharmony_ci	if (port[Port_cnt] & 0x008) {
469262306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
469362306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT set "
469462306a36Sopenharmony_ci			       "AIS report: card(%d) port(%d)\n",
469562306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
469662306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_REPORT_AIS,
469762306a36Sopenharmony_ci		    &hc->chan[hc->dnum[0]].cfg);
469862306a36Sopenharmony_ci	}
469962306a36Sopenharmony_ci	/* set SLIP report */
470062306a36Sopenharmony_ci	if (port[Port_cnt] & 0x010) {
470162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
470262306a36Sopenharmony_ci			printk(KERN_DEBUG
470362306a36Sopenharmony_ci			       "%s: PORT set SLIP report: "
470462306a36Sopenharmony_ci			       "card(%d) port(%d)\n",
470562306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
470662306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_REPORT_SLIP,
470762306a36Sopenharmony_ci		    &hc->chan[hc->dnum[0]].cfg);
470862306a36Sopenharmony_ci	}
470962306a36Sopenharmony_ci	/* set RDI report */
471062306a36Sopenharmony_ci	if (port[Port_cnt] & 0x020) {
471162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
471262306a36Sopenharmony_ci			printk(KERN_DEBUG
471362306a36Sopenharmony_ci			       "%s: PORT set RDI report: "
471462306a36Sopenharmony_ci			       "card(%d) port(%d)\n",
471562306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
471662306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_REPORT_RDI,
471762306a36Sopenharmony_ci		    &hc->chan[hc->dnum[0]].cfg);
471862306a36Sopenharmony_ci	}
471962306a36Sopenharmony_ci	/* set CRC-4 Mode */
472062306a36Sopenharmony_ci	if (!(port[Port_cnt] & 0x100)) {
472162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
472262306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT turn on CRC4 report:"
472362306a36Sopenharmony_ci			       " card(%d) port(%d)\n",
472462306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
472562306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_CRC4,
472662306a36Sopenharmony_ci		    &hc->chan[hc->dnum[0]].cfg);
472762306a36Sopenharmony_ci	} else {
472862306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
472962306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT turn off CRC4"
473062306a36Sopenharmony_ci			       " report: card(%d) port(%d)\n",
473162306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
473262306a36Sopenharmony_ci	}
473362306a36Sopenharmony_ci	/* set forced clock */
473462306a36Sopenharmony_ci	if (port[Port_cnt] & 0x0200) {
473562306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
473662306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT force getting clock from "
473762306a36Sopenharmony_ci			       "E1: card(%d) port(%d)\n",
473862306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
473962306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip);
474062306a36Sopenharmony_ci	} else
474162306a36Sopenharmony_ci		if (port[Port_cnt] & 0x0400) {
474262306a36Sopenharmony_ci			if (debug & DEBUG_HFCMULTI_INIT)
474362306a36Sopenharmony_ci				printk(KERN_DEBUG "%s: PORT force putting clock to "
474462306a36Sopenharmony_ci				       "E1: card(%d) port(%d)\n",
474562306a36Sopenharmony_ci				       __func__, HFC_cnt + 1, 1);
474662306a36Sopenharmony_ci			test_and_set_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip);
474762306a36Sopenharmony_ci		}
474862306a36Sopenharmony_ci	/* set JATT PLL */
474962306a36Sopenharmony_ci	if (port[Port_cnt] & 0x0800) {
475062306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
475162306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: PORT disable JATT PLL on "
475262306a36Sopenharmony_ci			       "E1: card(%d) port(%d)\n",
475362306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, 1);
475462306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip);
475562306a36Sopenharmony_ci	}
475662306a36Sopenharmony_ci	/* set elastic jitter buffer */
475762306a36Sopenharmony_ci	if (port[Port_cnt] & 0x3000) {
475862306a36Sopenharmony_ci		hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3;
475962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
476062306a36Sopenharmony_ci			printk(KERN_DEBUG
476162306a36Sopenharmony_ci			       "%s: PORT set elastic "
476262306a36Sopenharmony_ci			       "buffer to %d: card(%d) port(%d)\n",
476362306a36Sopenharmony_ci			    __func__, hc->chan[hc->dnum[0]].jitter,
476462306a36Sopenharmony_ci			       HFC_cnt + 1, 1);
476562306a36Sopenharmony_ci	} else
476662306a36Sopenharmony_ci		hc->chan[hc->dnum[0]].jitter = 2; /* default */
476762306a36Sopenharmony_ci}
476862306a36Sopenharmony_ci
476962306a36Sopenharmony_cistatic int
477062306a36Sopenharmony_ciinit_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
477162306a36Sopenharmony_ci{
477262306a36Sopenharmony_ci	struct dchannel	*dch;
477362306a36Sopenharmony_ci	struct bchannel	*bch;
477462306a36Sopenharmony_ci	int		ch, ret = 0;
477562306a36Sopenharmony_ci	char		name[MISDN_MAX_IDLEN];
477662306a36Sopenharmony_ci	int		bcount = 0;
477762306a36Sopenharmony_ci
477862306a36Sopenharmony_ci	dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL);
477962306a36Sopenharmony_ci	if (!dch)
478062306a36Sopenharmony_ci		return -ENOMEM;
478162306a36Sopenharmony_ci	dch->debug = debug;
478262306a36Sopenharmony_ci	mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
478362306a36Sopenharmony_ci	dch->hw = hc;
478462306a36Sopenharmony_ci	dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
478562306a36Sopenharmony_ci	dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
478662306a36Sopenharmony_ci	    (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
478762306a36Sopenharmony_ci	dch->dev.D.send = handle_dmsg;
478862306a36Sopenharmony_ci	dch->dev.D.ctrl = hfcm_dctrl;
478962306a36Sopenharmony_ci	dch->slot = hc->dnum[pt];
479062306a36Sopenharmony_ci	hc->chan[hc->dnum[pt]].dch = dch;
479162306a36Sopenharmony_ci	hc->chan[hc->dnum[pt]].port = pt;
479262306a36Sopenharmony_ci	hc->chan[hc->dnum[pt]].nt_timer = -1;
479362306a36Sopenharmony_ci	for (ch = 1; ch <= 31; ch++) {
479462306a36Sopenharmony_ci		if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */
479562306a36Sopenharmony_ci			continue;
479662306a36Sopenharmony_ci		bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL);
479762306a36Sopenharmony_ci		if (!bch) {
479862306a36Sopenharmony_ci			printk(KERN_ERR "%s: no memory for bchannel\n",
479962306a36Sopenharmony_ci			    __func__);
480062306a36Sopenharmony_ci			ret = -ENOMEM;
480162306a36Sopenharmony_ci			goto free_chan;
480262306a36Sopenharmony_ci		}
480362306a36Sopenharmony_ci		hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL);
480462306a36Sopenharmony_ci		if (!hc->chan[ch].coeff) {
480562306a36Sopenharmony_ci			printk(KERN_ERR "%s: no memory for coeffs\n",
480662306a36Sopenharmony_ci			    __func__);
480762306a36Sopenharmony_ci			ret = -ENOMEM;
480862306a36Sopenharmony_ci			kfree(bch);
480962306a36Sopenharmony_ci			goto free_chan;
481062306a36Sopenharmony_ci		}
481162306a36Sopenharmony_ci		bch->nr = ch;
481262306a36Sopenharmony_ci		bch->slot = ch;
481362306a36Sopenharmony_ci		bch->debug = debug;
481462306a36Sopenharmony_ci		mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1);
481562306a36Sopenharmony_ci		bch->hw = hc;
481662306a36Sopenharmony_ci		bch->ch.send = handle_bmsg;
481762306a36Sopenharmony_ci		bch->ch.ctrl = hfcm_bctrl;
481862306a36Sopenharmony_ci		bch->ch.nr = ch;
481962306a36Sopenharmony_ci		list_add(&bch->ch.list, &dch->dev.bchannels);
482062306a36Sopenharmony_ci		hc->chan[ch].bch = bch;
482162306a36Sopenharmony_ci		hc->chan[ch].port = pt;
482262306a36Sopenharmony_ci		set_channelmap(bch->nr, dch->dev.channelmap);
482362306a36Sopenharmony_ci		bcount++;
482462306a36Sopenharmony_ci	}
482562306a36Sopenharmony_ci	dch->dev.nrbchan = bcount;
482662306a36Sopenharmony_ci	if (pt == 0)
482762306a36Sopenharmony_ci		init_e1_port_hw(hc, m);
482862306a36Sopenharmony_ci	if (hc->ports > 1)
482962306a36Sopenharmony_ci		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d",
483062306a36Sopenharmony_ci				HFC_cnt + 1, pt+1);
483162306a36Sopenharmony_ci	else
483262306a36Sopenharmony_ci		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1);
483362306a36Sopenharmony_ci	ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
483462306a36Sopenharmony_ci	if (ret)
483562306a36Sopenharmony_ci		goto free_chan;
483662306a36Sopenharmony_ci	hc->created[pt] = 1;
483762306a36Sopenharmony_ci	return ret;
483862306a36Sopenharmony_cifree_chan:
483962306a36Sopenharmony_ci	release_port(hc, dch);
484062306a36Sopenharmony_ci	return ret;
484162306a36Sopenharmony_ci}
484262306a36Sopenharmony_ci
484362306a36Sopenharmony_cistatic int
484462306a36Sopenharmony_ciinit_multi_port(struct hfc_multi *hc, int pt)
484562306a36Sopenharmony_ci{
484662306a36Sopenharmony_ci	struct dchannel	*dch;
484762306a36Sopenharmony_ci	struct bchannel	*bch;
484862306a36Sopenharmony_ci	int		ch, i, ret = 0;
484962306a36Sopenharmony_ci	char		name[MISDN_MAX_IDLEN];
485062306a36Sopenharmony_ci
485162306a36Sopenharmony_ci	dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL);
485262306a36Sopenharmony_ci	if (!dch)
485362306a36Sopenharmony_ci		return -ENOMEM;
485462306a36Sopenharmony_ci	dch->debug = debug;
485562306a36Sopenharmony_ci	mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
485662306a36Sopenharmony_ci	dch->hw = hc;
485762306a36Sopenharmony_ci	dch->dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
485862306a36Sopenharmony_ci	dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
485962306a36Sopenharmony_ci		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
486062306a36Sopenharmony_ci	dch->dev.D.send = handle_dmsg;
486162306a36Sopenharmony_ci	dch->dev.D.ctrl = hfcm_dctrl;
486262306a36Sopenharmony_ci	dch->dev.nrbchan = 2;
486362306a36Sopenharmony_ci	i = pt << 2;
486462306a36Sopenharmony_ci	dch->slot = i + 2;
486562306a36Sopenharmony_ci	hc->chan[i + 2].dch = dch;
486662306a36Sopenharmony_ci	hc->chan[i + 2].port = pt;
486762306a36Sopenharmony_ci	hc->chan[i + 2].nt_timer = -1;
486862306a36Sopenharmony_ci	for (ch = 0; ch < dch->dev.nrbchan; ch++) {
486962306a36Sopenharmony_ci		bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL);
487062306a36Sopenharmony_ci		if (!bch) {
487162306a36Sopenharmony_ci			printk(KERN_ERR "%s: no memory for bchannel\n",
487262306a36Sopenharmony_ci			       __func__);
487362306a36Sopenharmony_ci			ret = -ENOMEM;
487462306a36Sopenharmony_ci			goto free_chan;
487562306a36Sopenharmony_ci		}
487662306a36Sopenharmony_ci		hc->chan[i + ch].coeff = kzalloc(512, GFP_KERNEL);
487762306a36Sopenharmony_ci		if (!hc->chan[i + ch].coeff) {
487862306a36Sopenharmony_ci			printk(KERN_ERR "%s: no memory for coeffs\n",
487962306a36Sopenharmony_ci			       __func__);
488062306a36Sopenharmony_ci			ret = -ENOMEM;
488162306a36Sopenharmony_ci			kfree(bch);
488262306a36Sopenharmony_ci			goto free_chan;
488362306a36Sopenharmony_ci		}
488462306a36Sopenharmony_ci		bch->nr = ch + 1;
488562306a36Sopenharmony_ci		bch->slot = i + ch;
488662306a36Sopenharmony_ci		bch->debug = debug;
488762306a36Sopenharmony_ci		mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1);
488862306a36Sopenharmony_ci		bch->hw = hc;
488962306a36Sopenharmony_ci		bch->ch.send = handle_bmsg;
489062306a36Sopenharmony_ci		bch->ch.ctrl = hfcm_bctrl;
489162306a36Sopenharmony_ci		bch->ch.nr = ch + 1;
489262306a36Sopenharmony_ci		list_add(&bch->ch.list, &dch->dev.bchannels);
489362306a36Sopenharmony_ci		hc->chan[i + ch].bch = bch;
489462306a36Sopenharmony_ci		hc->chan[i + ch].port = pt;
489562306a36Sopenharmony_ci		set_channelmap(bch->nr, dch->dev.channelmap);
489662306a36Sopenharmony_ci	}
489762306a36Sopenharmony_ci	/* set master clock */
489862306a36Sopenharmony_ci	if (port[Port_cnt] & 0x001) {
489962306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
490062306a36Sopenharmony_ci			printk(KERN_DEBUG
490162306a36Sopenharmony_ci			       "%s: PROTOCOL set master clock: "
490262306a36Sopenharmony_ci			       "card(%d) port(%d)\n",
490362306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, pt + 1);
490462306a36Sopenharmony_ci		if (dch->dev.D.protocol != ISDN_P_TE_S0) {
490562306a36Sopenharmony_ci			printk(KERN_ERR "Error: Master clock "
490662306a36Sopenharmony_ci			       "for port(%d) of card(%d) is only"
490762306a36Sopenharmony_ci			       " possible with TE-mode\n",
490862306a36Sopenharmony_ci			       pt + 1, HFC_cnt + 1);
490962306a36Sopenharmony_ci			ret = -EINVAL;
491062306a36Sopenharmony_ci			goto free_chan;
491162306a36Sopenharmony_ci		}
491262306a36Sopenharmony_ci		if (hc->masterclk >= 0) {
491362306a36Sopenharmony_ci			printk(KERN_ERR "Error: Master clock "
491462306a36Sopenharmony_ci			       "for port(%d) of card(%d) already "
491562306a36Sopenharmony_ci			       "defined for port(%d)\n",
491662306a36Sopenharmony_ci			       pt + 1, HFC_cnt + 1, hc->masterclk + 1);
491762306a36Sopenharmony_ci			ret = -EINVAL;
491862306a36Sopenharmony_ci			goto free_chan;
491962306a36Sopenharmony_ci		}
492062306a36Sopenharmony_ci		hc->masterclk = pt;
492162306a36Sopenharmony_ci	}
492262306a36Sopenharmony_ci	/* set transmitter line to non capacitive */
492362306a36Sopenharmony_ci	if (port[Port_cnt] & 0x002) {
492462306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
492562306a36Sopenharmony_ci			printk(KERN_DEBUG
492662306a36Sopenharmony_ci			       "%s: PROTOCOL set non capacitive "
492762306a36Sopenharmony_ci			       "transmitter: card(%d) port(%d)\n",
492862306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, pt + 1);
492962306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_NONCAP_TX,
493062306a36Sopenharmony_ci				 &hc->chan[i + 2].cfg);
493162306a36Sopenharmony_ci	}
493262306a36Sopenharmony_ci	/* disable E-channel */
493362306a36Sopenharmony_ci	if (port[Port_cnt] & 0x004) {
493462306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
493562306a36Sopenharmony_ci			printk(KERN_DEBUG
493662306a36Sopenharmony_ci			       "%s: PROTOCOL disable E-channel: "
493762306a36Sopenharmony_ci			       "card(%d) port(%d)\n",
493862306a36Sopenharmony_ci			       __func__, HFC_cnt + 1, pt + 1);
493962306a36Sopenharmony_ci		test_and_set_bit(HFC_CFG_DIS_ECHANNEL,
494062306a36Sopenharmony_ci				 &hc->chan[i + 2].cfg);
494162306a36Sopenharmony_ci	}
494262306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_XHFC) {
494362306a36Sopenharmony_ci		snprintf(name, MISDN_MAX_IDLEN - 1, "xhfc.%d-%d",
494462306a36Sopenharmony_ci			 HFC_cnt + 1, pt + 1);
494562306a36Sopenharmony_ci		ret = mISDN_register_device(&dch->dev, NULL, name);
494662306a36Sopenharmony_ci	} else {
494762306a36Sopenharmony_ci		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d",
494862306a36Sopenharmony_ci			 hc->ctype, HFC_cnt + 1, pt + 1);
494962306a36Sopenharmony_ci		ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
495062306a36Sopenharmony_ci	}
495162306a36Sopenharmony_ci	if (ret)
495262306a36Sopenharmony_ci		goto free_chan;
495362306a36Sopenharmony_ci	hc->created[pt] = 1;
495462306a36Sopenharmony_ci	return ret;
495562306a36Sopenharmony_cifree_chan:
495662306a36Sopenharmony_ci	release_port(hc, dch);
495762306a36Sopenharmony_ci	return ret;
495862306a36Sopenharmony_ci}
495962306a36Sopenharmony_ci
496062306a36Sopenharmony_cistatic int
496162306a36Sopenharmony_cihfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
496262306a36Sopenharmony_ci	      const struct pci_device_id *ent)
496362306a36Sopenharmony_ci{
496462306a36Sopenharmony_ci	int		ret_err = 0;
496562306a36Sopenharmony_ci	int		pt;
496662306a36Sopenharmony_ci	struct hfc_multi	*hc;
496762306a36Sopenharmony_ci	u_long		flags;
496862306a36Sopenharmony_ci	u_char		dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
496962306a36Sopenharmony_ci	int		i, ch;
497062306a36Sopenharmony_ci	u_int		maskcheck;
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	if (HFC_cnt >= MAX_CARDS) {
497362306a36Sopenharmony_ci		printk(KERN_ERR "too many cards (max=%d).\n",
497462306a36Sopenharmony_ci		       MAX_CARDS);
497562306a36Sopenharmony_ci		return -EINVAL;
497662306a36Sopenharmony_ci	}
497762306a36Sopenharmony_ci	if ((type[HFC_cnt] & 0xff) && (type[HFC_cnt] & 0xff) != m->type) {
497862306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-MULTI: Card '%s:%s' type %d found but "
497962306a36Sopenharmony_ci		       "type[%d] %d was supplied as module parameter\n",
498062306a36Sopenharmony_ci		       m->vendor_name, m->card_name, m->type, HFC_cnt,
498162306a36Sopenharmony_ci		       type[HFC_cnt] & 0xff);
498262306a36Sopenharmony_ci		printk(KERN_WARNING "HFC-MULTI: Load module without parameters "
498362306a36Sopenharmony_ci		       "first, to see cards and their types.");
498462306a36Sopenharmony_ci		return -EINVAL;
498562306a36Sopenharmony_ci	}
498662306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
498762306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: Registering %s:%s chip type %d (0x%x)\n",
498862306a36Sopenharmony_ci		       __func__, m->vendor_name, m->card_name, m->type,
498962306a36Sopenharmony_ci		       type[HFC_cnt]);
499062306a36Sopenharmony_ci
499162306a36Sopenharmony_ci	/* allocate card+fifo structure */
499262306a36Sopenharmony_ci	hc = kzalloc(sizeof(struct hfc_multi), GFP_KERNEL);
499362306a36Sopenharmony_ci	if (!hc) {
499462306a36Sopenharmony_ci		printk(KERN_ERR "No kmem for HFC-Multi card\n");
499562306a36Sopenharmony_ci		return -ENOMEM;
499662306a36Sopenharmony_ci	}
499762306a36Sopenharmony_ci	spin_lock_init(&hc->lock);
499862306a36Sopenharmony_ci	hc->mtyp = m;
499962306a36Sopenharmony_ci	hc->ctype =  m->type;
500062306a36Sopenharmony_ci	hc->ports = m->ports;
500162306a36Sopenharmony_ci	hc->id = HFC_cnt;
500262306a36Sopenharmony_ci	hc->pcm = pcm[HFC_cnt];
500362306a36Sopenharmony_ci	hc->io_mode = iomode[HFC_cnt];
500462306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) {
500562306a36Sopenharmony_ci		/* fragment card */
500662306a36Sopenharmony_ci		pt = 0;
500762306a36Sopenharmony_ci		maskcheck = 0;
500862306a36Sopenharmony_ci		for (ch = 0; ch <= 31; ch++) {
500962306a36Sopenharmony_ci			if (!((1 << ch) & dmask[E1_cnt]))
501062306a36Sopenharmony_ci				continue;
501162306a36Sopenharmony_ci			hc->dnum[pt] = ch;
501262306a36Sopenharmony_ci			hc->bmask[pt] = bmask[bmask_cnt++];
501362306a36Sopenharmony_ci			if ((maskcheck & hc->bmask[pt])
501462306a36Sopenharmony_ci			 || (dmask[E1_cnt] & hc->bmask[pt])) {
501562306a36Sopenharmony_ci				printk(KERN_INFO
501662306a36Sopenharmony_ci				       "HFC-E1 #%d has overlapping B-channels on fragment #%d\n",
501762306a36Sopenharmony_ci				       E1_cnt + 1, pt);
501862306a36Sopenharmony_ci				kfree(hc);
501962306a36Sopenharmony_ci				return -EINVAL;
502062306a36Sopenharmony_ci			}
502162306a36Sopenharmony_ci			maskcheck |= hc->bmask[pt];
502262306a36Sopenharmony_ci			printk(KERN_INFO
502362306a36Sopenharmony_ci			       "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n",
502462306a36Sopenharmony_ci				E1_cnt + 1, ch, hc->bmask[pt]);
502562306a36Sopenharmony_ci			pt++;
502662306a36Sopenharmony_ci		}
502762306a36Sopenharmony_ci		hc->ports = pt;
502862306a36Sopenharmony_ci	}
502962306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) {
503062306a36Sopenharmony_ci		/* default card layout */
503162306a36Sopenharmony_ci		hc->dnum[0] = 16;
503262306a36Sopenharmony_ci		hc->bmask[0] = 0xfffefffe;
503362306a36Sopenharmony_ci		hc->ports = 1;
503462306a36Sopenharmony_ci	}
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_ci	/* set chip specific features */
503762306a36Sopenharmony_ci	hc->masterclk = -1;
503862306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x100) {
503962306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
504062306a36Sopenharmony_ci		hc->silence = 0xff; /* ulaw silence */
504162306a36Sopenharmony_ci	} else
504262306a36Sopenharmony_ci		hc->silence = 0x2a; /* alaw silence */
504362306a36Sopenharmony_ci	if ((poll >> 1) > sizeof(hc->silence_data)) {
504462306a36Sopenharmony_ci		printk(KERN_ERR "HFCMULTI error: silence_data too small, "
504562306a36Sopenharmony_ci		       "please fix\n");
504662306a36Sopenharmony_ci		kfree(hc);
504762306a36Sopenharmony_ci		return -EINVAL;
504862306a36Sopenharmony_ci	}
504962306a36Sopenharmony_ci	for (i = 0; i < (poll >> 1); i++)
505062306a36Sopenharmony_ci		hc->silence_data[i] = hc->silence;
505162306a36Sopenharmony_ci
505262306a36Sopenharmony_ci	if (hc->ctype != HFC_TYPE_XHFC) {
505362306a36Sopenharmony_ci		if (!(type[HFC_cnt] & 0x200))
505462306a36Sopenharmony_ci			test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
505562306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_CONF, &hc->chip);
505662306a36Sopenharmony_ci	}
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x800)
505962306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
506062306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x1000) {
506162306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_PCM_MASTER, &hc->chip);
506262306a36Sopenharmony_ci		test_and_clear_bit(HFC_CHIP_PCM_SLAVE, &hc->chip);
506362306a36Sopenharmony_ci	}
506462306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x4000)
506562306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip);
506662306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x8000)
506762306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip);
506862306a36Sopenharmony_ci	hc->slots = 32;
506962306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x10000)
507062306a36Sopenharmony_ci		hc->slots = 64;
507162306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x20000)
507262306a36Sopenharmony_ci		hc->slots = 128;
507362306a36Sopenharmony_ci	if (type[HFC_cnt] & 0x80000) {
507462306a36Sopenharmony_ci		test_and_set_bit(HFC_CHIP_WATCHDOG, &hc->chip);
507562306a36Sopenharmony_ci		hc->wdcount = 0;
507662306a36Sopenharmony_ci		hc->wdbyte = V_GPIO_OUT2;
507762306a36Sopenharmony_ci		printk(KERN_NOTICE "Watchdog enabled\n");
507862306a36Sopenharmony_ci	}
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci	if (pdev && ent)
508162306a36Sopenharmony_ci		/* setup pci, hc->slots may change due to PLXSD */
508262306a36Sopenharmony_ci		ret_err = setup_pci(hc, pdev, ent);
508362306a36Sopenharmony_ci	else
508462306a36Sopenharmony_ci#ifdef CONFIG_MISDN_HFCMULTI_8xx
508562306a36Sopenharmony_ci		ret_err = setup_embedded(hc, m);
508662306a36Sopenharmony_ci#else
508762306a36Sopenharmony_ci	{
508862306a36Sopenharmony_ci		printk(KERN_WARNING "Embedded IO Mode not selected\n");
508962306a36Sopenharmony_ci		ret_err = -EIO;
509062306a36Sopenharmony_ci	}
509162306a36Sopenharmony_ci#endif
509262306a36Sopenharmony_ci	if (ret_err) {
509362306a36Sopenharmony_ci		if (hc == syncmaster)
509462306a36Sopenharmony_ci			syncmaster = NULL;
509562306a36Sopenharmony_ci		kfree(hc);
509662306a36Sopenharmony_ci		return ret_err;
509762306a36Sopenharmony_ci	}
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	hc->HFC_outb_nodebug = hc->HFC_outb;
510062306a36Sopenharmony_ci	hc->HFC_inb_nodebug = hc->HFC_inb;
510162306a36Sopenharmony_ci	hc->HFC_inw_nodebug = hc->HFC_inw;
510262306a36Sopenharmony_ci	hc->HFC_wait_nodebug = hc->HFC_wait;
510362306a36Sopenharmony_ci#ifdef HFC_REGISTER_DEBUG
510462306a36Sopenharmony_ci	hc->HFC_outb = HFC_outb_debug;
510562306a36Sopenharmony_ci	hc->HFC_inb = HFC_inb_debug;
510662306a36Sopenharmony_ci	hc->HFC_inw = HFC_inw_debug;
510762306a36Sopenharmony_ci	hc->HFC_wait = HFC_wait_debug;
510862306a36Sopenharmony_ci#endif
510962306a36Sopenharmony_ci	/* create channels */
511062306a36Sopenharmony_ci	for (pt = 0; pt < hc->ports; pt++) {
511162306a36Sopenharmony_ci		if (Port_cnt >= MAX_PORTS) {
511262306a36Sopenharmony_ci			printk(KERN_ERR "too many ports (max=%d).\n",
511362306a36Sopenharmony_ci			       MAX_PORTS);
511462306a36Sopenharmony_ci			ret_err = -EINVAL;
511562306a36Sopenharmony_ci			goto free_card;
511662306a36Sopenharmony_ci		}
511762306a36Sopenharmony_ci		if (hc->ctype == HFC_TYPE_E1)
511862306a36Sopenharmony_ci			ret_err = init_e1_port(hc, m, pt);
511962306a36Sopenharmony_ci		else
512062306a36Sopenharmony_ci			ret_err = init_multi_port(hc, pt);
512162306a36Sopenharmony_ci		if (debug & DEBUG_HFCMULTI_INIT)
512262306a36Sopenharmony_ci			printk(KERN_DEBUG
512362306a36Sopenharmony_ci			    "%s: Registering D-channel, card(%d) port(%d) "
512462306a36Sopenharmony_ci			       "result %d\n",
512562306a36Sopenharmony_ci			    __func__, HFC_cnt + 1, pt + 1, ret_err);
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci		if (ret_err) {
512862306a36Sopenharmony_ci			while (pt) { /* release already registered ports */
512962306a36Sopenharmony_ci				pt--;
513062306a36Sopenharmony_ci				if (hc->ctype == HFC_TYPE_E1)
513162306a36Sopenharmony_ci					release_port(hc,
513262306a36Sopenharmony_ci						hc->chan[hc->dnum[pt]].dch);
513362306a36Sopenharmony_ci				else
513462306a36Sopenharmony_ci					release_port(hc,
513562306a36Sopenharmony_ci						hc->chan[(pt << 2) + 2].dch);
513662306a36Sopenharmony_ci			}
513762306a36Sopenharmony_ci			goto free_card;
513862306a36Sopenharmony_ci		}
513962306a36Sopenharmony_ci		if (hc->ctype != HFC_TYPE_E1)
514062306a36Sopenharmony_ci			Port_cnt++; /* for each S0 port */
514162306a36Sopenharmony_ci	}
514262306a36Sopenharmony_ci	if (hc->ctype == HFC_TYPE_E1) {
514362306a36Sopenharmony_ci		Port_cnt++; /* for each E1 port */
514462306a36Sopenharmony_ci		E1_cnt++;
514562306a36Sopenharmony_ci	}
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_ci	/* disp switches */
514862306a36Sopenharmony_ci	switch (m->dip_type) {
514962306a36Sopenharmony_ci	case DIP_4S:
515062306a36Sopenharmony_ci		/*
515162306a36Sopenharmony_ci		 * Get DIP setting for beroNet 1S/2S/4S cards
515262306a36Sopenharmony_ci		 * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) +
515362306a36Sopenharmony_ci		 * GPI 19/23 (R_GPI_IN2))
515462306a36Sopenharmony_ci		 */
515562306a36Sopenharmony_ci		dips = ((~HFC_inb(hc, R_GPIO_IN1) & 0xE0) >> 5) |
515662306a36Sopenharmony_ci			((~HFC_inb(hc, R_GPI_IN2) & 0x80) >> 3) |
515762306a36Sopenharmony_ci			(~HFC_inb(hc, R_GPI_IN2) & 0x08);
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_ci		/* Port mode (TE/NT) jumpers */
516062306a36Sopenharmony_ci		pmj = ((HFC_inb(hc, R_GPI_IN3) >> 4)  & 0xf);
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci		if (test_bit(HFC_CHIP_B410P, &hc->chip))
516362306a36Sopenharmony_ci			pmj = ~pmj & 0xf;
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci		printk(KERN_INFO "%s: %s DIPs(0x%x) jumpers(0x%x)\n",
516662306a36Sopenharmony_ci		       m->vendor_name, m->card_name, dips, pmj);
516762306a36Sopenharmony_ci		break;
516862306a36Sopenharmony_ci	case DIP_8S:
516962306a36Sopenharmony_ci		/*
517062306a36Sopenharmony_ci		 * Get DIP Setting for beroNet 8S0+ cards
517162306a36Sopenharmony_ci		 * Enable PCI auxbridge function
517262306a36Sopenharmony_ci		 */
517362306a36Sopenharmony_ci		HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
517462306a36Sopenharmony_ci		/* prepare access to auxport */
517562306a36Sopenharmony_ci		outw(0x4000, hc->pci_iobase + 4);
517662306a36Sopenharmony_ci		/*
517762306a36Sopenharmony_ci		 * some dummy reads are required to
517862306a36Sopenharmony_ci		 * read valid DIP switch data
517962306a36Sopenharmony_ci		 */
518062306a36Sopenharmony_ci		dips = inb(hc->pci_iobase);
518162306a36Sopenharmony_ci		dips = inb(hc->pci_iobase);
518262306a36Sopenharmony_ci		dips = inb(hc->pci_iobase);
518362306a36Sopenharmony_ci		dips = ~inb(hc->pci_iobase) & 0x3F;
518462306a36Sopenharmony_ci		outw(0x0, hc->pci_iobase + 4);
518562306a36Sopenharmony_ci		/* disable PCI auxbridge function */
518662306a36Sopenharmony_ci		HFC_outb(hc, R_BRG_PCM_CFG, V_PCM_CLK);
518762306a36Sopenharmony_ci		printk(KERN_INFO "%s: %s DIPs(0x%x)\n",
518862306a36Sopenharmony_ci		       m->vendor_name, m->card_name, dips);
518962306a36Sopenharmony_ci		break;
519062306a36Sopenharmony_ci	case DIP_E1:
519162306a36Sopenharmony_ci		/*
519262306a36Sopenharmony_ci		 * get DIP Setting for beroNet E1 cards
519362306a36Sopenharmony_ci		 * DIP Setting: collect GPI 4/5/6/7 (R_GPI_IN0)
519462306a36Sopenharmony_ci		 */
519562306a36Sopenharmony_ci		dips = (~HFC_inb(hc, R_GPI_IN0) & 0xF0) >> 4;
519662306a36Sopenharmony_ci		printk(KERN_INFO "%s: %s DIPs(0x%x)\n",
519762306a36Sopenharmony_ci		       m->vendor_name, m->card_name, dips);
519862306a36Sopenharmony_ci		break;
519962306a36Sopenharmony_ci	}
520062306a36Sopenharmony_ci
520162306a36Sopenharmony_ci	/* add to list */
520262306a36Sopenharmony_ci	spin_lock_irqsave(&HFClock, flags);
520362306a36Sopenharmony_ci	list_add_tail(&hc->list, &HFClist);
520462306a36Sopenharmony_ci	spin_unlock_irqrestore(&HFClock, flags);
520562306a36Sopenharmony_ci
520662306a36Sopenharmony_ci	/* use as clock source */
520762306a36Sopenharmony_ci	if (clock == HFC_cnt + 1)
520862306a36Sopenharmony_ci		hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc);
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci	/* initialize hardware */
521162306a36Sopenharmony_ci	hc->irq = (m->irq) ? : hc->pci_dev->irq;
521262306a36Sopenharmony_ci	ret_err = init_card(hc);
521362306a36Sopenharmony_ci	if (ret_err) {
521462306a36Sopenharmony_ci		printk(KERN_ERR "init card returns %d\n", ret_err);
521562306a36Sopenharmony_ci		release_card(hc);
521662306a36Sopenharmony_ci		return ret_err;
521762306a36Sopenharmony_ci	}
521862306a36Sopenharmony_ci
521962306a36Sopenharmony_ci	/* start IRQ and return */
522062306a36Sopenharmony_ci	spin_lock_irqsave(&hc->lock, flags);
522162306a36Sopenharmony_ci	enable_hwirq(hc);
522262306a36Sopenharmony_ci	spin_unlock_irqrestore(&hc->lock, flags);
522362306a36Sopenharmony_ci	return 0;
522462306a36Sopenharmony_ci
522562306a36Sopenharmony_cifree_card:
522662306a36Sopenharmony_ci	release_io_hfcmulti(hc);
522762306a36Sopenharmony_ci	if (hc == syncmaster)
522862306a36Sopenharmony_ci		syncmaster = NULL;
522962306a36Sopenharmony_ci	kfree(hc);
523062306a36Sopenharmony_ci	return ret_err;
523162306a36Sopenharmony_ci}
523262306a36Sopenharmony_ci
523362306a36Sopenharmony_cistatic void hfc_remove_pci(struct pci_dev *pdev)
523462306a36Sopenharmony_ci{
523562306a36Sopenharmony_ci	struct hfc_multi	*card = pci_get_drvdata(pdev);
523662306a36Sopenharmony_ci	u_long			flags;
523762306a36Sopenharmony_ci
523862306a36Sopenharmony_ci	if (debug)
523962306a36Sopenharmony_ci		printk(KERN_INFO "removing hfc_multi card vendor:%x "
524062306a36Sopenharmony_ci		       "device:%x subvendor:%x subdevice:%x\n",
524162306a36Sopenharmony_ci		       pdev->vendor, pdev->device,
524262306a36Sopenharmony_ci		       pdev->subsystem_vendor, pdev->subsystem_device);
524362306a36Sopenharmony_ci
524462306a36Sopenharmony_ci	if (card) {
524562306a36Sopenharmony_ci		spin_lock_irqsave(&HFClock, flags);
524662306a36Sopenharmony_ci		release_card(card);
524762306a36Sopenharmony_ci		spin_unlock_irqrestore(&HFClock, flags);
524862306a36Sopenharmony_ci	}  else {
524962306a36Sopenharmony_ci		if (debug)
525062306a36Sopenharmony_ci			printk(KERN_DEBUG "%s: drvdata already removed\n",
525162306a36Sopenharmony_ci			       __func__);
525262306a36Sopenharmony_ci	}
525362306a36Sopenharmony_ci}
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_ci#define	VENDOR_CCD	"Cologne Chip AG"
525662306a36Sopenharmony_ci#define	VENDOR_BN	"beroNet GmbH"
525762306a36Sopenharmony_ci#define	VENDOR_DIG	"Digium Inc."
525862306a36Sopenharmony_ci#define VENDOR_JH	"Junghanns.NET GmbH"
525962306a36Sopenharmony_ci#define VENDOR_PRIM	"PrimuX"
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_cistatic const struct hm_map hfcm_map[] = {
526262306a36Sopenharmony_ci	/*0*/	{VENDOR_BN, "HFC-1S Card (mini PCI)", 4, 1, 1, 3, 0, DIP_4S, 0, 0},
526362306a36Sopenharmony_ci	/*1*/	{VENDOR_BN, "HFC-2S Card", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
526462306a36Sopenharmony_ci	/*2*/	{VENDOR_BN, "HFC-2S Card (mini PCI)", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
526562306a36Sopenharmony_ci	/*3*/	{VENDOR_BN, "HFC-4S Card", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
526662306a36Sopenharmony_ci	/*4*/	{VENDOR_BN, "HFC-4S Card (mini PCI)", 4, 4, 1, 2, 0, 0, 0, 0},
526762306a36Sopenharmony_ci	/*5*/	{VENDOR_CCD, "HFC-4S Eval (old)", 4, 4, 0, 0, 0, 0, 0, 0},
526862306a36Sopenharmony_ci	/*6*/	{VENDOR_CCD, "HFC-4S IOB4ST", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
526962306a36Sopenharmony_ci	/*7*/	{VENDOR_CCD, "HFC-4S", 4, 4, 1, 2, 0, 0, 0, 0},
527062306a36Sopenharmony_ci	/*8*/	{VENDOR_DIG, "HFC-4S Card", 4, 4, 0, 2, 0, 0, HFC_IO_MODE_REGIO, 0},
527162306a36Sopenharmony_ci	/*9*/	{VENDOR_CCD, "HFC-4S Swyx 4xS0 SX2 QuadBri", 4, 4, 1, 2, 0, 0, 0, 0},
527262306a36Sopenharmony_ci	/*10*/	{VENDOR_JH, "HFC-4S (junghanns 2.0)", 4, 4, 1, 2, 0, 0, 0, 0},
527362306a36Sopenharmony_ci	/*11*/	{VENDOR_PRIM, "HFC-2S Primux Card", 4, 2, 0, 0, 0, 0, 0, 0},
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ci	/*12*/	{VENDOR_BN, "HFC-8S Card", 8, 8, 1, 0, 0, 0, 0, 0},
527662306a36Sopenharmony_ci	/*13*/	{VENDOR_BN, "HFC-8S Card (+)", 8, 8, 1, 8, 0, DIP_8S,
527762306a36Sopenharmony_ci		 HFC_IO_MODE_REGIO, 0},
527862306a36Sopenharmony_ci	/*14*/	{VENDOR_CCD, "HFC-8S Eval (old)", 8, 8, 0, 0, 0, 0, 0, 0},
527962306a36Sopenharmony_ci	/*15*/	{VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 8, 1, 0, 0, 0, 0, 0},
528062306a36Sopenharmony_ci
528162306a36Sopenharmony_ci	/*16*/	{VENDOR_CCD, "HFC-8S IOB8ST", 8, 8, 1, 0, 0, 0, 0, 0},
528262306a36Sopenharmony_ci	/*17*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
528362306a36Sopenharmony_ci	/*18*/	{VENDOR_CCD, "HFC-8S", 8, 8, 1, 0, 0, 0, 0, 0},
528462306a36Sopenharmony_ci
528562306a36Sopenharmony_ci	/*19*/	{VENDOR_BN, "HFC-E1 Card", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
528662306a36Sopenharmony_ci	/*20*/	{VENDOR_BN, "HFC-E1 Card (mini PCI)", 1, 1, 0, 1, 0, 0, 0, 0},
528762306a36Sopenharmony_ci	/*21*/	{VENDOR_BN, "HFC-E1+ Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
528862306a36Sopenharmony_ci	/*22*/	{VENDOR_BN, "HFC-E1 Card (Dual)", 1, 1, 0, 1, 0, DIP_E1, 0, 0},
528962306a36Sopenharmony_ci
529062306a36Sopenharmony_ci	/*23*/	{VENDOR_CCD, "HFC-E1 Eval (old)", 1, 1, 0, 0, 0, 0, 0, 0},
529162306a36Sopenharmony_ci	/*24*/	{VENDOR_CCD, "HFC-E1 IOB1E1", 1, 1, 0, 1, 0, 0, 0, 0},
529262306a36Sopenharmony_ci	/*25*/	{VENDOR_CCD, "HFC-E1", 1, 1, 0, 1, 0, 0, 0, 0},
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	/*26*/	{VENDOR_CCD, "HFC-4S Speech Design", 4, 4, 0, 0, 0, 0,
529562306a36Sopenharmony_ci		 HFC_IO_MODE_PLXSD, 0},
529662306a36Sopenharmony_ci	/*27*/	{VENDOR_CCD, "HFC-E1 Speech Design", 1, 1, 0, 0, 0, 0,
529762306a36Sopenharmony_ci		 HFC_IO_MODE_PLXSD, 0},
529862306a36Sopenharmony_ci	/*28*/	{VENDOR_CCD, "HFC-4S OpenVox", 4, 4, 1, 0, 0, 0, 0, 0},
529962306a36Sopenharmony_ci	/*29*/	{VENDOR_CCD, "HFC-2S OpenVox", 4, 2, 1, 0, 0, 0, 0, 0},
530062306a36Sopenharmony_ci	/*30*/	{VENDOR_CCD, "HFC-8S OpenVox", 8, 8, 1, 0, 0, 0, 0, 0},
530162306a36Sopenharmony_ci	/*31*/	{VENDOR_CCD, "XHFC-4S Speech Design", 5, 4, 0, 0, 0, 0,
530262306a36Sopenharmony_ci		 HFC_IO_MODE_EMBSD, XHFC_IRQ},
530362306a36Sopenharmony_ci	/*32*/	{VENDOR_JH, "HFC-8S (junghanns)", 8, 8, 1, 0, 0, 0, 0, 0},
530462306a36Sopenharmony_ci	/*33*/	{VENDOR_BN, "HFC-2S Beronet Card PCIe", 4, 2, 1, 3, 0, DIP_4S, 0, 0},
530562306a36Sopenharmony_ci	/*34*/	{VENDOR_BN, "HFC-4S Beronet Card PCIe", 4, 4, 1, 2, 0, DIP_4S, 0, 0},
530662306a36Sopenharmony_ci};
530762306a36Sopenharmony_ci
530862306a36Sopenharmony_ci#undef H
530962306a36Sopenharmony_ci#define H(x)	((unsigned long)&hfcm_map[x])
531062306a36Sopenharmony_cistatic const struct pci_device_id hfmultipci_ids[] = {
531162306a36Sopenharmony_ci
531262306a36Sopenharmony_ci	/* Cards with HFC-4S Chip */
531362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
531462306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN1SM, 0, 0, H(0)}, /* BN1S mini PCI */
531562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
531662306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN2S, 0, 0, H(1)}, /* BN2S */
531762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
531862306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN2SM, 0, 0, H(2)}, /* BN2S mini PCI */
531962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
532062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN4S, 0, 0, H(3)}, /* BN4S */
532162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
532262306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN4SM, 0, 0, H(4)}, /* BN4S mini PCI */
532362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
532462306a36Sopenharmony_ci	  PCI_DEVICE_ID_CCD_HFC4S, 0, 0, H(5)}, /* Old Eval */
532562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
532662306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_IOB4ST, 0, 0, H(6)}, /* IOB4ST */
532762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
532862306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_HFC4S, 0, 0, H(7)}, /* 4S */
532962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S,
533062306a36Sopenharmony_ci	  PCI_VENDOR_ID_DIGIUM, PCI_DEVICE_ID_DIGIUM_HFC4S, 0, 0, H(8)},
533162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
533262306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_SWYX4S, 0, 0, H(9)}, /* 4S Swyx */
533362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
533462306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_JH4S20, 0, 0, H(10)},
533562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
533662306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_PMX2S, 0, 0, H(11)}, /* Primux */
533762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
533862306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_OV4S, 0, 0, H(28)}, /* OpenVox 4 */
533962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
534062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_OV2S, 0, 0, H(29)}, /* OpenVox 2 */
534162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
534262306a36Sopenharmony_ci	  0xb761, 0, 0, H(33)}, /* BN2S PCIe */
534362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
534462306a36Sopenharmony_ci	  0xb762, 0, 0, H(34)}, /* BN4S PCIe */
534562306a36Sopenharmony_ci
534662306a36Sopenharmony_ci	/* Cards with HFC-8S Chip */
534762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
534862306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN8S, 0, 0, H(12)}, /* BN8S */
534962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
535062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BN8SP, 0, 0, H(13)}, /* BN8S+ */
535162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
535262306a36Sopenharmony_ci	  PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */
535362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
535462306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */
535562306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
535662306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST  */
535762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
535862306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_IOB8ST_1, 0, 0, H(17)}, /* IOB8ST  */
535962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
536062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_HFC8S, 0, 0, H(18)}, /* 8S */
536162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
536262306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_OV8S, 0, 0, H(30)}, /* OpenVox 8 */
536362306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
536462306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_JH8S, 0, 0, H(32)}, /* Junganns 8S  */
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci	/* Cards with HFC-E1 Chip */
536862306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
536962306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BNE1, 0, 0, H(19)}, /* BNE1 */
537062306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
537162306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BNE1M, 0, 0, H(20)}, /* BNE1 mini PCI */
537262306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
537362306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BNE1DP, 0, 0, H(21)}, /* BNE1 + (Dual) */
537462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
537562306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_BNE1D, 0, 0, H(22)}, /* BNE1 (Dual) */
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
537862306a36Sopenharmony_ci	  PCI_DEVICE_ID_CCD_HFCE1, 0, 0, H(23)}, /* Old Eval */
537962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
538062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_IOB1E1, 0, 0, H(24)}, /* IOB1E1 */
538162306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
538262306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_HFCE1, 0, 0, H(25)}, /* E1 */
538362306a36Sopenharmony_ci
538462306a36Sopenharmony_ci	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD,
538562306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_SPD4S, 0, 0, H(26)}, /* PLX PCI Bridge */
538662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_CCD,
538762306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_SPDE1, 0, 0, H(27)}, /* PLX PCI Bridge */
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFCE1, PCI_VENDOR_ID_CCD,
539062306a36Sopenharmony_ci	  PCI_SUBDEVICE_ID_CCD_JHSE1, 0, 0, H(25)}, /* Junghanns E1 */
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC4S), 0 },
539362306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFC8S), 0 },
539462306a36Sopenharmony_ci	{ PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_HFCE1), 0 },
539562306a36Sopenharmony_ci	{0, }
539662306a36Sopenharmony_ci};
539762306a36Sopenharmony_ci#undef H
539862306a36Sopenharmony_ci
539962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hfmultipci_ids);
540062306a36Sopenharmony_ci
540162306a36Sopenharmony_cistatic int
540262306a36Sopenharmony_cihfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
540362306a36Sopenharmony_ci{
540462306a36Sopenharmony_ci	struct hm_map	*m = (struct hm_map *)ent->driver_data;
540562306a36Sopenharmony_ci	int		ret;
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci	if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && (
540862306a36Sopenharmony_ci		    ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
540962306a36Sopenharmony_ci		    ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
541062306a36Sopenharmony_ci		    ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
541162306a36Sopenharmony_ci		printk(KERN_ERR
541262306a36Sopenharmony_ci		       "Unknown HFC multiport controller (vendor:%04x device:%04x "
541362306a36Sopenharmony_ci		       "subvendor:%04x subdevice:%04x)\n", pdev->vendor,
541462306a36Sopenharmony_ci		       pdev->device, pdev->subsystem_vendor,
541562306a36Sopenharmony_ci		       pdev->subsystem_device);
541662306a36Sopenharmony_ci		printk(KERN_ERR
541762306a36Sopenharmony_ci		       "Please contact the driver maintainer for support.\n");
541862306a36Sopenharmony_ci		return -ENODEV;
541962306a36Sopenharmony_ci	}
542062306a36Sopenharmony_ci	ret = hfcmulti_init(m, pdev, ent);
542162306a36Sopenharmony_ci	if (ret)
542262306a36Sopenharmony_ci		return ret;
542362306a36Sopenharmony_ci	HFC_cnt++;
542462306a36Sopenharmony_ci	printk(KERN_INFO "%d devices registered\n", HFC_cnt);
542562306a36Sopenharmony_ci	return 0;
542662306a36Sopenharmony_ci}
542762306a36Sopenharmony_ci
542862306a36Sopenharmony_cistatic struct pci_driver hfcmultipci_driver = {
542962306a36Sopenharmony_ci	.name		= "hfc_multi",
543062306a36Sopenharmony_ci	.probe		= hfcmulti_probe,
543162306a36Sopenharmony_ci	.remove		= hfc_remove_pci,
543262306a36Sopenharmony_ci	.id_table	= hfmultipci_ids,
543362306a36Sopenharmony_ci};
543462306a36Sopenharmony_ci
543562306a36Sopenharmony_cistatic void __exit
543662306a36Sopenharmony_ciHFCmulti_cleanup(void)
543762306a36Sopenharmony_ci{
543862306a36Sopenharmony_ci	struct hfc_multi *card, *next;
543962306a36Sopenharmony_ci
544062306a36Sopenharmony_ci	/* get rid of all devices of this driver */
544162306a36Sopenharmony_ci	list_for_each_entry_safe(card, next, &HFClist, list)
544262306a36Sopenharmony_ci		release_card(card);
544362306a36Sopenharmony_ci	pci_unregister_driver(&hfcmultipci_driver);
544462306a36Sopenharmony_ci}
544562306a36Sopenharmony_ci
544662306a36Sopenharmony_cistatic int __init
544762306a36Sopenharmony_ciHFCmulti_init(void)
544862306a36Sopenharmony_ci{
544962306a36Sopenharmony_ci	int err;
545062306a36Sopenharmony_ci	int i, xhfc = 0;
545162306a36Sopenharmony_ci	struct hm_map m;
545262306a36Sopenharmony_ci
545362306a36Sopenharmony_ci	printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION);
545462306a36Sopenharmony_ci
545562306a36Sopenharmony_ci#ifdef IRQ_DEBUG
545662306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
545762306a36Sopenharmony_ci#endif
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_ci	if (debug & DEBUG_HFCMULTI_INIT)
546062306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: init entered\n", __func__);
546162306a36Sopenharmony_ci
546262306a36Sopenharmony_ci	switch (poll) {
546362306a36Sopenharmony_ci	case 0:
546462306a36Sopenharmony_ci		poll_timer = 6;
546562306a36Sopenharmony_ci		poll = 128;
546662306a36Sopenharmony_ci		break;
546762306a36Sopenharmony_ci	case 8:
546862306a36Sopenharmony_ci		poll_timer = 2;
546962306a36Sopenharmony_ci		break;
547062306a36Sopenharmony_ci	case 16:
547162306a36Sopenharmony_ci		poll_timer = 3;
547262306a36Sopenharmony_ci		break;
547362306a36Sopenharmony_ci	case 32:
547462306a36Sopenharmony_ci		poll_timer = 4;
547562306a36Sopenharmony_ci		break;
547662306a36Sopenharmony_ci	case 64:
547762306a36Sopenharmony_ci		poll_timer = 5;
547862306a36Sopenharmony_ci		break;
547962306a36Sopenharmony_ci	case 128:
548062306a36Sopenharmony_ci		poll_timer = 6;
548162306a36Sopenharmony_ci		break;
548262306a36Sopenharmony_ci	case 256:
548362306a36Sopenharmony_ci		poll_timer = 7;
548462306a36Sopenharmony_ci		break;
548562306a36Sopenharmony_ci	default:
548662306a36Sopenharmony_ci		printk(KERN_ERR
548762306a36Sopenharmony_ci		       "%s: Wrong poll value (%d).\n", __func__, poll);
548862306a36Sopenharmony_ci		err = -EINVAL;
548962306a36Sopenharmony_ci		return err;
549062306a36Sopenharmony_ci
549162306a36Sopenharmony_ci	}
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	if (!clock)
549462306a36Sopenharmony_ci		clock = 1;
549562306a36Sopenharmony_ci
549662306a36Sopenharmony_ci	/* Register the embedded devices.
549762306a36Sopenharmony_ci	 * This should be done before the PCI cards registration */
549862306a36Sopenharmony_ci	switch (hwid) {
549962306a36Sopenharmony_ci	case HWID_MINIP4:
550062306a36Sopenharmony_ci		xhfc = 1;
550162306a36Sopenharmony_ci		m = hfcm_map[31];
550262306a36Sopenharmony_ci		break;
550362306a36Sopenharmony_ci	case HWID_MINIP8:
550462306a36Sopenharmony_ci		xhfc = 2;
550562306a36Sopenharmony_ci		m = hfcm_map[31];
550662306a36Sopenharmony_ci		break;
550762306a36Sopenharmony_ci	case HWID_MINIP16:
550862306a36Sopenharmony_ci		xhfc = 4;
550962306a36Sopenharmony_ci		m = hfcm_map[31];
551062306a36Sopenharmony_ci		break;
551162306a36Sopenharmony_ci	default:
551262306a36Sopenharmony_ci		xhfc = 0;
551362306a36Sopenharmony_ci	}
551462306a36Sopenharmony_ci
551562306a36Sopenharmony_ci	for (i = 0; i < xhfc; ++i) {
551662306a36Sopenharmony_ci		err = hfcmulti_init(&m, NULL, NULL);
551762306a36Sopenharmony_ci		if (err) {
551862306a36Sopenharmony_ci			printk(KERN_ERR "error registering embedded driver: "
551962306a36Sopenharmony_ci			       "%x\n", err);
552062306a36Sopenharmony_ci			return err;
552162306a36Sopenharmony_ci		}
552262306a36Sopenharmony_ci		HFC_cnt++;
552362306a36Sopenharmony_ci		printk(KERN_INFO "%d devices registered\n", HFC_cnt);
552462306a36Sopenharmony_ci	}
552562306a36Sopenharmony_ci
552662306a36Sopenharmony_ci	/* Register the PCI cards */
552762306a36Sopenharmony_ci	err = pci_register_driver(&hfcmultipci_driver);
552862306a36Sopenharmony_ci	if (err < 0) {
552962306a36Sopenharmony_ci		printk(KERN_ERR "error registering pci driver: %x\n", err);
553062306a36Sopenharmony_ci		return err;
553162306a36Sopenharmony_ci	}
553262306a36Sopenharmony_ci
553362306a36Sopenharmony_ci	return 0;
553462306a36Sopenharmony_ci}
553562306a36Sopenharmony_ci
553662306a36Sopenharmony_ci
553762306a36Sopenharmony_cimodule_init(HFCmulti_init);
553862306a36Sopenharmony_cimodule_exit(HFCmulti_cleanup);
5539