18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * mISDNinfineon.c
48c2ecf20Sopenharmony_ci *		Support for cards based on following Infineon ISDN chipsets
58c2ecf20Sopenharmony_ci *		- ISAC + HSCX
68c2ecf20Sopenharmony_ci *		- IPAC and IPAC-X
78c2ecf20Sopenharmony_ci *		- ISAC-SX + HSCX
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Supported cards:
108c2ecf20Sopenharmony_ci *		- Dialogic Diva 2.0
118c2ecf20Sopenharmony_ci *		- Dialogic Diva 2.0U
128c2ecf20Sopenharmony_ci *		- Dialogic Diva 2.01
138c2ecf20Sopenharmony_ci *		- Dialogic Diva 2.02
148c2ecf20Sopenharmony_ci *		- Sedlbauer Speedwin
158c2ecf20Sopenharmony_ci *		- HST Saphir3
168c2ecf20Sopenharmony_ci *		- Develo (former ELSA) Microlink PCI (Quickstep 1000)
178c2ecf20Sopenharmony_ci *		- Develo (former ELSA) Quickstep 3000
188c2ecf20Sopenharmony_ci *		- Berkom Scitel BRIX Quadro
198c2ecf20Sopenharmony_ci *		- Dr.Neuhaus (Sagem) Niccy
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Author       Karsten Keil <keil@isdn4linux.de>
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Copyright 2009  by Karsten Keil <keil@isdn4linux.de>
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/pci.h>
298c2ecf20Sopenharmony_ci#include <linux/delay.h>
308c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h>
318c2ecf20Sopenharmony_ci#include <linux/slab.h>
328c2ecf20Sopenharmony_ci#include "ipac.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define INFINEON_REV	"1.0"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int inf_cnt;
378c2ecf20Sopenharmony_cistatic u32 debug;
388c2ecf20Sopenharmony_cistatic u32 irqloops = 4;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cienum inf_types {
418c2ecf20Sopenharmony_ci	INF_NONE,
428c2ecf20Sopenharmony_ci	INF_DIVA20,
438c2ecf20Sopenharmony_ci	INF_DIVA20U,
448c2ecf20Sopenharmony_ci	INF_DIVA201,
458c2ecf20Sopenharmony_ci	INF_DIVA202,
468c2ecf20Sopenharmony_ci	INF_SPEEDWIN,
478c2ecf20Sopenharmony_ci	INF_SAPHIR3,
488c2ecf20Sopenharmony_ci	INF_QS1000,
498c2ecf20Sopenharmony_ci	INF_QS3000,
508c2ecf20Sopenharmony_ci	INF_NICCY,
518c2ecf20Sopenharmony_ci	INF_SCT_1,
528c2ecf20Sopenharmony_ci	INF_SCT_2,
538c2ecf20Sopenharmony_ci	INF_SCT_3,
548c2ecf20Sopenharmony_ci	INF_SCT_4,
558c2ecf20Sopenharmony_ci	INF_GAZEL_R685,
568c2ecf20Sopenharmony_ci	INF_GAZEL_R753
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cienum addr_mode {
608c2ecf20Sopenharmony_ci	AM_NONE = 0,
618c2ecf20Sopenharmony_ci	AM_IO,
628c2ecf20Sopenharmony_ci	AM_MEMIO,
638c2ecf20Sopenharmony_ci	AM_IND_IO,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct inf_cinfo {
678c2ecf20Sopenharmony_ci	enum inf_types	typ;
688c2ecf20Sopenharmony_ci	const char	*full;
698c2ecf20Sopenharmony_ci	const char	*name;
708c2ecf20Sopenharmony_ci	enum addr_mode	cfg_mode;
718c2ecf20Sopenharmony_ci	enum addr_mode	addr_mode;
728c2ecf20Sopenharmony_ci	u8		cfg_bar;
738c2ecf20Sopenharmony_ci	u8		addr_bar;
748c2ecf20Sopenharmony_ci	void		*irqfunc;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct _ioaddr {
788c2ecf20Sopenharmony_ci	enum addr_mode	mode;
798c2ecf20Sopenharmony_ci	union {
808c2ecf20Sopenharmony_ci		void __iomem	*p;
818c2ecf20Sopenharmony_ci		struct _ioport	io;
828c2ecf20Sopenharmony_ci	} a;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct _iohandle {
868c2ecf20Sopenharmony_ci	enum addr_mode	mode;
878c2ecf20Sopenharmony_ci	resource_size_t	size;
888c2ecf20Sopenharmony_ci	resource_size_t	start;
898c2ecf20Sopenharmony_ci	void __iomem	*p;
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistruct inf_hw {
938c2ecf20Sopenharmony_ci	struct list_head	list;
948c2ecf20Sopenharmony_ci	struct pci_dev		*pdev;
958c2ecf20Sopenharmony_ci	const struct inf_cinfo	*ci;
968c2ecf20Sopenharmony_ci	char			name[MISDN_MAX_IDLEN];
978c2ecf20Sopenharmony_ci	u32			irq;
988c2ecf20Sopenharmony_ci	u32			irqcnt;
998c2ecf20Sopenharmony_ci	struct _iohandle	cfg;
1008c2ecf20Sopenharmony_ci	struct _iohandle	addr;
1018c2ecf20Sopenharmony_ci	struct _ioaddr		isac;
1028c2ecf20Sopenharmony_ci	struct _ioaddr		hscx;
1038c2ecf20Sopenharmony_ci	spinlock_t		lock;	/* HW access lock */
1048c2ecf20Sopenharmony_ci	struct ipac_hw		ipac;
1058c2ecf20Sopenharmony_ci	struct inf_hw		*sc[3];	/* slave cards */
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define PCI_SUBVENDOR_HST_SAPHIR3       0x52
1108c2ecf20Sopenharmony_ci#define PCI_SUBVENDOR_SEDLBAUER_PCI     0x53
1118c2ecf20Sopenharmony_ci#define PCI_SUB_ID_SEDLBAUER            0x01
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct pci_device_id infineon_ids[] = {
1148c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },
1158c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },
1168c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },
1178c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },
1188c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
1198c2ecf20Sopenharmony_ci	  PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
1208c2ecf20Sopenharmony_ci	  INF_SPEEDWIN },
1218c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
1228c2ecf20Sopenharmony_ci	  PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },
1238c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },
1248c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },
1258c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },
1268c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
1278c2ecf20Sopenharmony_ci	  PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
1288c2ecf20Sopenharmony_ci	  INF_SCT_1 },
1298c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },
1308c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },
1318c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },
1328c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },
1338c2ecf20Sopenharmony_ci	{ }
1348c2ecf20Sopenharmony_ci};
1358c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, infineon_ids);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* PCI interface specific defines */
1388c2ecf20Sopenharmony_ci/* Diva 2.0/2.0U */
1398c2ecf20Sopenharmony_ci#define DIVA_HSCX_PORT		0x00
1408c2ecf20Sopenharmony_ci#define DIVA_HSCX_ALE		0x04
1418c2ecf20Sopenharmony_ci#define DIVA_ISAC_PORT		0x08
1428c2ecf20Sopenharmony_ci#define DIVA_ISAC_ALE		0x0C
1438c2ecf20Sopenharmony_ci#define DIVA_PCI_CTRL           0x10
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* DIVA_PCI_CTRL bits */
1468c2ecf20Sopenharmony_ci#define DIVA_IRQ_BIT		0x01
1478c2ecf20Sopenharmony_ci#define DIVA_RESET_BIT		0x08
1488c2ecf20Sopenharmony_ci#define DIVA_EEPROM_CLK		0x40
1498c2ecf20Sopenharmony_ci#define DIVA_LED_A		0x10
1508c2ecf20Sopenharmony_ci#define DIVA_LED_B		0x20
1518c2ecf20Sopenharmony_ci#define DIVA_IRQ_CLR		0x80
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/* Diva 2.01/2.02 */
1548c2ecf20Sopenharmony_ci/* Siemens PITA */
1558c2ecf20Sopenharmony_ci#define PITA_ICR_REG		0x00
1568c2ecf20Sopenharmony_ci#define PITA_INT0_STATUS	0x02
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#define PITA_MISC_REG		0x1c
1598c2ecf20Sopenharmony_ci#define PITA_PARA_SOFTRESET	0x01000000
1608c2ecf20Sopenharmony_ci#define PITA_SER_SOFTRESET	0x02000000
1618c2ecf20Sopenharmony_ci#define PITA_PARA_MPX_MODE	0x04000000
1628c2ecf20Sopenharmony_ci#define PITA_INT0_ENABLE	0x00020000
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* TIGER 100 Registers */
1658c2ecf20Sopenharmony_ci#define TIGER_RESET_ADDR	0x00
1668c2ecf20Sopenharmony_ci#define TIGER_EXTERN_RESET	0x01
1678c2ecf20Sopenharmony_ci#define TIGER_AUX_CTRL		0x02
1688c2ecf20Sopenharmony_ci#define TIGER_AUX_DATA		0x03
1698c2ecf20Sopenharmony_ci#define TIGER_AUX_IRQMASK	0x05
1708c2ecf20Sopenharmony_ci#define TIGER_AUX_STATUS	0x07
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* Tiger AUX BITs */
1738c2ecf20Sopenharmony_ci#define TIGER_IOMASK		0xdd	/* 1 and 5 are inputs */
1748c2ecf20Sopenharmony_ci#define TIGER_IRQ_BIT		0x02
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#define TIGER_IPAC_ALE		0xC0
1778c2ecf20Sopenharmony_ci#define TIGER_IPAC_PORT		0xC8
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/* ELSA (now Develo) PCI cards */
1808c2ecf20Sopenharmony_ci#define ELSA_IRQ_ADDR		0x4c
1818c2ecf20Sopenharmony_ci#define ELSA_IRQ_MASK		0x04
1828c2ecf20Sopenharmony_ci#define QS1000_IRQ_OFF		0x01
1838c2ecf20Sopenharmony_ci#define QS3000_IRQ_OFF		0x03
1848c2ecf20Sopenharmony_ci#define QS1000_IRQ_ON		0x41
1858c2ecf20Sopenharmony_ci#define QS3000_IRQ_ON		0x43
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/* Dr Neuhaus/Sagem Niccy */
1888c2ecf20Sopenharmony_ci#define NICCY_ISAC_PORT		0x00
1898c2ecf20Sopenharmony_ci#define NICCY_HSCX_PORT		0x01
1908c2ecf20Sopenharmony_ci#define NICCY_ISAC_ALE		0x02
1918c2ecf20Sopenharmony_ci#define NICCY_HSCX_ALE		0x03
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#define NICCY_IRQ_CTRL_REG	0x38
1948c2ecf20Sopenharmony_ci#define NICCY_IRQ_ENABLE	0x001f00
1958c2ecf20Sopenharmony_ci#define NICCY_IRQ_DISABLE	0xff0000
1968c2ecf20Sopenharmony_ci#define NICCY_IRQ_BIT		0x800000
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/* Scitel PLX */
2008c2ecf20Sopenharmony_ci#define SCT_PLX_IRQ_ADDR	0x4c
2018c2ecf20Sopenharmony_ci#define SCT_PLX_RESET_ADDR	0x50
2028c2ecf20Sopenharmony_ci#define SCT_PLX_IRQ_ENABLE	0x41
2038c2ecf20Sopenharmony_ci#define SCT_PLX_RESET_BIT	0x04
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/* Gazel */
2068c2ecf20Sopenharmony_ci#define	GAZEL_IPAC_DATA_PORT	0x04
2078c2ecf20Sopenharmony_ci/* Gazel PLX */
2088c2ecf20Sopenharmony_ci#define GAZEL_CNTRL		0x50
2098c2ecf20Sopenharmony_ci#define GAZEL_RESET		0x04
2108c2ecf20Sopenharmony_ci#define GAZEL_RESET_9050	0x40000000
2118c2ecf20Sopenharmony_ci#define GAZEL_INCSR		0x4C
2128c2ecf20Sopenharmony_ci#define GAZEL_ISAC_EN		0x08
2138c2ecf20Sopenharmony_ci#define GAZEL_INT_ISAC		0x20
2148c2ecf20Sopenharmony_ci#define GAZEL_HSCX_EN		0x01
2158c2ecf20Sopenharmony_ci#define GAZEL_INT_HSCX		0x04
2168c2ecf20Sopenharmony_ci#define GAZEL_PCI_EN		0x40
2178c2ecf20Sopenharmony_ci#define GAZEL_IPAC_EN		0x03
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic LIST_HEAD(Cards);
2218c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(card_lock); /* protect Cards */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void
2248c2ecf20Sopenharmony_ci_set_debug(struct inf_hw *card)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	card->ipac.isac.dch.debug = debug;
2278c2ecf20Sopenharmony_ci	card->ipac.hscx[0].bch.debug = debug;
2288c2ecf20Sopenharmony_ci	card->ipac.hscx[1].bch.debug = debug;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int
2328c2ecf20Sopenharmony_ciset_debug(const char *val, const struct kernel_param *kp)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	int ret;
2358c2ecf20Sopenharmony_ci	struct inf_hw *card;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	ret = param_set_uint(val, kp);
2388c2ecf20Sopenharmony_ci	if (!ret) {
2398c2ecf20Sopenharmony_ci		read_lock(&card_lock);
2408c2ecf20Sopenharmony_ci		list_for_each_entry(card, &Cards, list)
2418c2ecf20Sopenharmony_ci			_set_debug(card);
2428c2ecf20Sopenharmony_ci		read_unlock(&card_lock);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	return ret;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil");
2488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
2498c2ecf20Sopenharmony_ciMODULE_VERSION(INFINEON_REV);
2508c2ecf20Sopenharmony_cimodule_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
2518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "infineon debug mask");
2528c2ecf20Sopenharmony_cimodule_param(irqloops, uint, S_IRUGO | S_IWUSR);
2538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/* Interface functions */
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ciIOFUNC_IO(ISAC, inf_hw, isac.a.io)
2588c2ecf20Sopenharmony_ciIOFUNC_IO(IPAC, inf_hw, hscx.a.io)
2598c2ecf20Sopenharmony_ciIOFUNC_IND(ISAC, inf_hw, isac.a.io)
2608c2ecf20Sopenharmony_ciIOFUNC_IND(IPAC, inf_hw, hscx.a.io)
2618c2ecf20Sopenharmony_ciIOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
2628c2ecf20Sopenharmony_ciIOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic irqreturn_t
2658c2ecf20Sopenharmony_cidiva_irq(int intno, void *dev_id)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
2688c2ecf20Sopenharmony_ci	u8 val;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
2718c2ecf20Sopenharmony_ci	val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);
2728c2ecf20Sopenharmony_ci	if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */
2738c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
2748c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci	hw->irqcnt++;
2778c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
2788c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
2798c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic irqreturn_t
2838c2ecf20Sopenharmony_cidiva20x_irq(int intno, void *dev_id)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
2868c2ecf20Sopenharmony_ci	u8 val;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
2898c2ecf20Sopenharmony_ci	val = readb(hw->cfg.p);
2908c2ecf20Sopenharmony_ci	if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */
2918c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
2928c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	hw->irqcnt++;
2958c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
2968c2ecf20Sopenharmony_ci	writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */
2978c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
2988c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic irqreturn_t
3028c2ecf20Sopenharmony_citiger_irq(int intno, void *dev_id)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
3058c2ecf20Sopenharmony_ci	u8 val;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
3088c2ecf20Sopenharmony_ci	val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);
3098c2ecf20Sopenharmony_ci	if (val & TIGER_IRQ_BIT) { /* for us or shared ? */
3108c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
3118c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	hw->irqcnt++;
3148c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
3158c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
3168c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic irqreturn_t
3208c2ecf20Sopenharmony_cielsa_irq(int intno, void *dev_id)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
3238c2ecf20Sopenharmony_ci	u8 val;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
3268c2ecf20Sopenharmony_ci	val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);
3278c2ecf20Sopenharmony_ci	if (!(val & ELSA_IRQ_MASK)) {
3288c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
3298c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	hw->irqcnt++;
3328c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
3338c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
3348c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic irqreturn_t
3388c2ecf20Sopenharmony_ciniccy_irq(int intno, void *dev_id)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
3418c2ecf20Sopenharmony_ci	u32 val;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
3448c2ecf20Sopenharmony_ci	val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
3458c2ecf20Sopenharmony_ci	if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */
3468c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
3478c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
3508c2ecf20Sopenharmony_ci	hw->irqcnt++;
3518c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
3528c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
3538c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic irqreturn_t
3578c2ecf20Sopenharmony_cigazel_irq(int intno, void *dev_id)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
3608c2ecf20Sopenharmony_ci	irqreturn_t ret;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
3638c2ecf20Sopenharmony_ci	ret = mISDNipac_irq(&hw->ipac, irqloops);
3648c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
3658c2ecf20Sopenharmony_ci	return ret;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic irqreturn_t
3698c2ecf20Sopenharmony_ciipac_irq(int intno, void *dev_id)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct inf_hw *hw = dev_id;
3728c2ecf20Sopenharmony_ci	u8 val;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	spin_lock(&hw->lock);
3758c2ecf20Sopenharmony_ci	val = hw->ipac.read_reg(hw, IPAC_ISTA);
3768c2ecf20Sopenharmony_ci	if (!(val & 0x3f)) {
3778c2ecf20Sopenharmony_ci		spin_unlock(&hw->lock);
3788c2ecf20Sopenharmony_ci		return IRQ_NONE; /* shared */
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	hw->irqcnt++;
3818c2ecf20Sopenharmony_ci	mISDNipac_irq(&hw->ipac, irqloops);
3828c2ecf20Sopenharmony_ci	spin_unlock(&hw->lock);
3838c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void
3878c2ecf20Sopenharmony_cienable_hwirq(struct inf_hw *hw)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	u16 w;
3908c2ecf20Sopenharmony_ci	u32 val;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	switch (hw->ci->typ) {
3938c2ecf20Sopenharmony_ci	case INF_DIVA201:
3948c2ecf20Sopenharmony_ci	case INF_DIVA202:
3958c2ecf20Sopenharmony_ci		writel(PITA_INT0_ENABLE, hw->cfg.p);
3968c2ecf20Sopenharmony_ci		break;
3978c2ecf20Sopenharmony_ci	case INF_SPEEDWIN:
3988c2ecf20Sopenharmony_ci	case INF_SAPHIR3:
3998c2ecf20Sopenharmony_ci		outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
4008c2ecf20Sopenharmony_ci		break;
4018c2ecf20Sopenharmony_ci	case INF_QS1000:
4028c2ecf20Sopenharmony_ci		outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case INF_QS3000:
4058c2ecf20Sopenharmony_ci		outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	case INF_NICCY:
4088c2ecf20Sopenharmony_ci		val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
4098c2ecf20Sopenharmony_ci		val |= NICCY_IRQ_ENABLE;
4108c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	case INF_SCT_1:
4138c2ecf20Sopenharmony_ci		w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
4148c2ecf20Sopenharmony_ci		w |= SCT_PLX_IRQ_ENABLE;
4158c2ecf20Sopenharmony_ci		outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
4168c2ecf20Sopenharmony_ci		break;
4178c2ecf20Sopenharmony_ci	case INF_GAZEL_R685:
4188c2ecf20Sopenharmony_ci		outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,
4198c2ecf20Sopenharmony_ci		     (u32)hw->cfg.start + GAZEL_INCSR);
4208c2ecf20Sopenharmony_ci		break;
4218c2ecf20Sopenharmony_ci	case INF_GAZEL_R753:
4228c2ecf20Sopenharmony_ci		outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,
4238c2ecf20Sopenharmony_ci		     (u32)hw->cfg.start + GAZEL_INCSR);
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	default:
4268c2ecf20Sopenharmony_ci		break;
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic void
4318c2ecf20Sopenharmony_cidisable_hwirq(struct inf_hw *hw)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	u16 w;
4348c2ecf20Sopenharmony_ci	u32 val;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	switch (hw->ci->typ) {
4378c2ecf20Sopenharmony_ci	case INF_DIVA201:
4388c2ecf20Sopenharmony_ci	case INF_DIVA202:
4398c2ecf20Sopenharmony_ci		writel(0, hw->cfg.p);
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case INF_SPEEDWIN:
4428c2ecf20Sopenharmony_ci	case INF_SAPHIR3:
4438c2ecf20Sopenharmony_ci		outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci	case INF_QS1000:
4468c2ecf20Sopenharmony_ci		outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
4478c2ecf20Sopenharmony_ci		break;
4488c2ecf20Sopenharmony_ci	case INF_QS3000:
4498c2ecf20Sopenharmony_ci		outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
4508c2ecf20Sopenharmony_ci		break;
4518c2ecf20Sopenharmony_ci	case INF_NICCY:
4528c2ecf20Sopenharmony_ci		val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
4538c2ecf20Sopenharmony_ci		val &= NICCY_IRQ_DISABLE;
4548c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci	case INF_SCT_1:
4578c2ecf20Sopenharmony_ci		w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
4588c2ecf20Sopenharmony_ci		w &= (~SCT_PLX_IRQ_ENABLE);
4598c2ecf20Sopenharmony_ci		outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci	case INF_GAZEL_R685:
4628c2ecf20Sopenharmony_ci	case INF_GAZEL_R753:
4638c2ecf20Sopenharmony_ci		outb(0, (u32)hw->cfg.start + GAZEL_INCSR);
4648c2ecf20Sopenharmony_ci		break;
4658c2ecf20Sopenharmony_ci	default:
4668c2ecf20Sopenharmony_ci		break;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic void
4718c2ecf20Sopenharmony_ciipac_chip_reset(struct inf_hw *hw)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);
4748c2ecf20Sopenharmony_ci	mdelay(5);
4758c2ecf20Sopenharmony_ci	hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);
4768c2ecf20Sopenharmony_ci	mdelay(5);
4778c2ecf20Sopenharmony_ci	hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);
4788c2ecf20Sopenharmony_ci	hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic void
4828c2ecf20Sopenharmony_cireset_inf(struct inf_hw *hw)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	u16 w;
4858c2ecf20Sopenharmony_ci	u32 val;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (debug & DEBUG_HW)
4888c2ecf20Sopenharmony_ci		pr_notice("%s: resetting card\n", hw->name);
4898c2ecf20Sopenharmony_ci	switch (hw->ci->typ) {
4908c2ecf20Sopenharmony_ci	case INF_DIVA20:
4918c2ecf20Sopenharmony_ci	case INF_DIVA20U:
4928c2ecf20Sopenharmony_ci		outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);
4938c2ecf20Sopenharmony_ci		mdelay(10);
4948c2ecf20Sopenharmony_ci		outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);
4958c2ecf20Sopenharmony_ci		mdelay(10);
4968c2ecf20Sopenharmony_ci		/* Workaround PCI9060 */
4978c2ecf20Sopenharmony_ci		outb(9, (u32)hw->cfg.start + 0x69);
4988c2ecf20Sopenharmony_ci		outb(DIVA_RESET_BIT | DIVA_LED_A,
4998c2ecf20Sopenharmony_ci		     (u32)hw->cfg.start + DIVA_PCI_CTRL);
5008c2ecf20Sopenharmony_ci		break;
5018c2ecf20Sopenharmony_ci	case INF_DIVA201:
5028c2ecf20Sopenharmony_ci		writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
5038c2ecf20Sopenharmony_ci		       hw->cfg.p + PITA_MISC_REG);
5048c2ecf20Sopenharmony_ci		mdelay(1);
5058c2ecf20Sopenharmony_ci		writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);
5068c2ecf20Sopenharmony_ci		mdelay(10);
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci	case INF_DIVA202:
5098c2ecf20Sopenharmony_ci		writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
5108c2ecf20Sopenharmony_ci		       hw->cfg.p + PITA_MISC_REG);
5118c2ecf20Sopenharmony_ci		mdelay(1);
5128c2ecf20Sopenharmony_ci		writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,
5138c2ecf20Sopenharmony_ci		       hw->cfg.p + PITA_MISC_REG);
5148c2ecf20Sopenharmony_ci		mdelay(10);
5158c2ecf20Sopenharmony_ci		break;
5168c2ecf20Sopenharmony_ci	case INF_SPEEDWIN:
5178c2ecf20Sopenharmony_ci	case INF_SAPHIR3:
5188c2ecf20Sopenharmony_ci		ipac_chip_reset(hw);
5198c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
5208c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
5218c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci	case INF_QS1000:
5248c2ecf20Sopenharmony_ci	case INF_QS3000:
5258c2ecf20Sopenharmony_ci		ipac_chip_reset(hw);
5268c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);
5278c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);
5288c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_ATX, 0xff);
5298c2ecf20Sopenharmony_ci		break;
5308c2ecf20Sopenharmony_ci	case INF_NICCY:
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	case INF_SCT_1:
5338c2ecf20Sopenharmony_ci		w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
5348c2ecf20Sopenharmony_ci		w &= (~SCT_PLX_RESET_BIT);
5358c2ecf20Sopenharmony_ci		outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
5368c2ecf20Sopenharmony_ci		mdelay(10);
5378c2ecf20Sopenharmony_ci		w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
5388c2ecf20Sopenharmony_ci		w |= SCT_PLX_RESET_BIT;
5398c2ecf20Sopenharmony_ci		outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
5408c2ecf20Sopenharmony_ci		mdelay(10);
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	case INF_GAZEL_R685:
5438c2ecf20Sopenharmony_ci		val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
5448c2ecf20Sopenharmony_ci		val |= (GAZEL_RESET_9050 + GAZEL_RESET);
5458c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
5468c2ecf20Sopenharmony_ci		val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
5478c2ecf20Sopenharmony_ci		mdelay(4);
5488c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
5498c2ecf20Sopenharmony_ci		mdelay(10);
5508c2ecf20Sopenharmony_ci		hw->ipac.isac.adf2 = 0x87;
5518c2ecf20Sopenharmony_ci		hw->ipac.hscx[0].slot = 0x1f;
5528c2ecf20Sopenharmony_ci		hw->ipac.hscx[1].slot = 0x23;
5538c2ecf20Sopenharmony_ci		break;
5548c2ecf20Sopenharmony_ci	case INF_GAZEL_R753:
5558c2ecf20Sopenharmony_ci		val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
5568c2ecf20Sopenharmony_ci		val |= (GAZEL_RESET_9050 + GAZEL_RESET);
5578c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
5588c2ecf20Sopenharmony_ci		val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
5598c2ecf20Sopenharmony_ci		mdelay(4);
5608c2ecf20Sopenharmony_ci		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
5618c2ecf20Sopenharmony_ci		mdelay(10);
5628c2ecf20Sopenharmony_ci		ipac_chip_reset(hw);
5638c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
5648c2ecf20Sopenharmony_ci		hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
5658c2ecf20Sopenharmony_ci		hw->ipac.conf = 0x01; /* IOM off */
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	default:
5688c2ecf20Sopenharmony_ci		return;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci	enable_hwirq(hw);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic int
5748c2ecf20Sopenharmony_ciinf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	int ret = 0;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	switch (cmd) {
5798c2ecf20Sopenharmony_ci	case HW_RESET_REQ:
5808c2ecf20Sopenharmony_ci		reset_inf(hw);
5818c2ecf20Sopenharmony_ci		break;
5828c2ecf20Sopenharmony_ci	default:
5838c2ecf20Sopenharmony_ci		pr_info("%s: %s unknown command %x %lx\n",
5848c2ecf20Sopenharmony_ci			hw->name, __func__, cmd, arg);
5858c2ecf20Sopenharmony_ci		ret = -EINVAL;
5868c2ecf20Sopenharmony_ci		break;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci	return ret;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic int
5928c2ecf20Sopenharmony_ciinit_irq(struct inf_hw *hw)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	int	ret, cnt = 3;
5958c2ecf20Sopenharmony_ci	u_long	flags;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (!hw->ci->irqfunc)
5988c2ecf20Sopenharmony_ci		return -EINVAL;
5998c2ecf20Sopenharmony_ci	ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);
6008c2ecf20Sopenharmony_ci	if (ret) {
6018c2ecf20Sopenharmony_ci		pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);
6028c2ecf20Sopenharmony_ci		return ret;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	while (cnt--) {
6058c2ecf20Sopenharmony_ci		spin_lock_irqsave(&hw->lock, flags);
6068c2ecf20Sopenharmony_ci		reset_inf(hw);
6078c2ecf20Sopenharmony_ci		ret = hw->ipac.init(&hw->ipac);
6088c2ecf20Sopenharmony_ci		if (ret) {
6098c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&hw->lock, flags);
6108c2ecf20Sopenharmony_ci			pr_info("%s: ISAC init failed with %d\n",
6118c2ecf20Sopenharmony_ci				hw->name, ret);
6128c2ecf20Sopenharmony_ci			break;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&hw->lock, flags);
6158c2ecf20Sopenharmony_ci		msleep_interruptible(10);
6168c2ecf20Sopenharmony_ci		if (debug & DEBUG_HW)
6178c2ecf20Sopenharmony_ci			pr_notice("%s: IRQ %d count %d\n", hw->name,
6188c2ecf20Sopenharmony_ci				  hw->irq, hw->irqcnt);
6198c2ecf20Sopenharmony_ci		if (!hw->irqcnt) {
6208c2ecf20Sopenharmony_ci			pr_info("%s: IRQ(%d) got no requests during init %d\n",
6218c2ecf20Sopenharmony_ci				hw->name, hw->irq, 3 - cnt);
6228c2ecf20Sopenharmony_ci		} else
6238c2ecf20Sopenharmony_ci			return 0;
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci	free_irq(hw->irq, hw);
6268c2ecf20Sopenharmony_ci	return -EIO;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic void
6308c2ecf20Sopenharmony_cirelease_io(struct inf_hw *hw)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	if (hw->cfg.mode) {
6338c2ecf20Sopenharmony_ci		if (hw->cfg.mode == AM_MEMIO) {
6348c2ecf20Sopenharmony_ci			release_mem_region(hw->cfg.start, hw->cfg.size);
6358c2ecf20Sopenharmony_ci			if (hw->cfg.p)
6368c2ecf20Sopenharmony_ci				iounmap(hw->cfg.p);
6378c2ecf20Sopenharmony_ci		} else
6388c2ecf20Sopenharmony_ci			release_region(hw->cfg.start, hw->cfg.size);
6398c2ecf20Sopenharmony_ci		hw->cfg.mode = AM_NONE;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci	if (hw->addr.mode) {
6428c2ecf20Sopenharmony_ci		if (hw->addr.mode == AM_MEMIO) {
6438c2ecf20Sopenharmony_ci			release_mem_region(hw->addr.start, hw->addr.size);
6448c2ecf20Sopenharmony_ci			if (hw->addr.p)
6458c2ecf20Sopenharmony_ci				iounmap(hw->addr.p);
6468c2ecf20Sopenharmony_ci		} else
6478c2ecf20Sopenharmony_ci			release_region(hw->addr.start, hw->addr.size);
6488c2ecf20Sopenharmony_ci		hw->addr.mode = AM_NONE;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic int
6538c2ecf20Sopenharmony_cisetup_io(struct inf_hw *hw)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	int err = 0;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (hw->ci->cfg_mode) {
6588c2ecf20Sopenharmony_ci		hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);
6598c2ecf20Sopenharmony_ci		hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);
6608c2ecf20Sopenharmony_ci		if (hw->ci->cfg_mode == AM_MEMIO) {
6618c2ecf20Sopenharmony_ci			if (!request_mem_region(hw->cfg.start, hw->cfg.size,
6628c2ecf20Sopenharmony_ci						hw->name))
6638c2ecf20Sopenharmony_ci				err = -EBUSY;
6648c2ecf20Sopenharmony_ci		} else {
6658c2ecf20Sopenharmony_ci			if (!request_region(hw->cfg.start, hw->cfg.size,
6668c2ecf20Sopenharmony_ci					    hw->name))
6678c2ecf20Sopenharmony_ci				err = -EBUSY;
6688c2ecf20Sopenharmony_ci		}
6698c2ecf20Sopenharmony_ci		if (err) {
6708c2ecf20Sopenharmony_ci			pr_info("mISDN: %s config port %lx (%lu bytes)"
6718c2ecf20Sopenharmony_ci				"already in use\n", hw->name,
6728c2ecf20Sopenharmony_ci				(ulong)hw->cfg.start, (ulong)hw->cfg.size);
6738c2ecf20Sopenharmony_ci			return err;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci		hw->cfg.mode = hw->ci->cfg_mode;
6768c2ecf20Sopenharmony_ci		if (hw->ci->cfg_mode == AM_MEMIO) {
6778c2ecf20Sopenharmony_ci			hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
6788c2ecf20Sopenharmony_ci			if (!hw->cfg.p)
6798c2ecf20Sopenharmony_ci				return -ENOMEM;
6808c2ecf20Sopenharmony_ci		}
6818c2ecf20Sopenharmony_ci		if (debug & DEBUG_HW)
6828c2ecf20Sopenharmony_ci			pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",
6838c2ecf20Sopenharmony_ci				  hw->name, (ulong)hw->cfg.start,
6848c2ecf20Sopenharmony_ci				  (ulong)hw->cfg.size, hw->ci->cfg_mode);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci	if (hw->ci->addr_mode) {
6888c2ecf20Sopenharmony_ci		hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);
6898c2ecf20Sopenharmony_ci		hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);
6908c2ecf20Sopenharmony_ci		if (hw->ci->addr_mode == AM_MEMIO) {
6918c2ecf20Sopenharmony_ci			if (!request_mem_region(hw->addr.start, hw->addr.size,
6928c2ecf20Sopenharmony_ci						hw->name))
6938c2ecf20Sopenharmony_ci				err = -EBUSY;
6948c2ecf20Sopenharmony_ci		} else {
6958c2ecf20Sopenharmony_ci			if (!request_region(hw->addr.start, hw->addr.size,
6968c2ecf20Sopenharmony_ci					    hw->name))
6978c2ecf20Sopenharmony_ci				err = -EBUSY;
6988c2ecf20Sopenharmony_ci		}
6998c2ecf20Sopenharmony_ci		if (err) {
7008c2ecf20Sopenharmony_ci			pr_info("mISDN: %s address port %lx (%lu bytes)"
7018c2ecf20Sopenharmony_ci				"already in use\n", hw->name,
7028c2ecf20Sopenharmony_ci				(ulong)hw->addr.start, (ulong)hw->addr.size);
7038c2ecf20Sopenharmony_ci			return err;
7048c2ecf20Sopenharmony_ci		}
7058c2ecf20Sopenharmony_ci		hw->addr.mode = hw->ci->addr_mode;
7068c2ecf20Sopenharmony_ci		if (hw->ci->addr_mode == AM_MEMIO) {
7078c2ecf20Sopenharmony_ci			hw->addr.p = ioremap(hw->addr.start, hw->addr.size);
7088c2ecf20Sopenharmony_ci			if (!hw->addr.p)
7098c2ecf20Sopenharmony_ci				return -ENOMEM;
7108c2ecf20Sopenharmony_ci		}
7118c2ecf20Sopenharmony_ci		if (debug & DEBUG_HW)
7128c2ecf20Sopenharmony_ci			pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",
7138c2ecf20Sopenharmony_ci				  hw->name, (ulong)hw->addr.start,
7148c2ecf20Sopenharmony_ci				  (ulong)hw->addr.size, hw->ci->addr_mode);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	switch (hw->ci->typ) {
7198c2ecf20Sopenharmony_ci	case INF_DIVA20:
7208c2ecf20Sopenharmony_ci	case INF_DIVA20U:
7218c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
7228c2ecf20Sopenharmony_ci		hw->isac.mode = hw->cfg.mode;
7238c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;
7248c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;
7258c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->cfg.mode;
7268c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;
7278c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;
7288c2ecf20Sopenharmony_ci		break;
7298c2ecf20Sopenharmony_ci	case INF_DIVA201:
7308c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
7318c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
7328c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7338c2ecf20Sopenharmony_ci		hw->isac.a.p = hw->addr.p;
7348c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7358c2ecf20Sopenharmony_ci		hw->hscx.a.p = hw->addr.p;
7368c2ecf20Sopenharmony_ci		break;
7378c2ecf20Sopenharmony_ci	case INF_DIVA202:
7388c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPACX;
7398c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7408c2ecf20Sopenharmony_ci		hw->isac.a.p = hw->addr.p;
7418c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7428c2ecf20Sopenharmony_ci		hw->hscx.a.p = hw->addr.p;
7438c2ecf20Sopenharmony_ci		break;
7448c2ecf20Sopenharmony_ci	case INF_SPEEDWIN:
7458c2ecf20Sopenharmony_ci	case INF_SAPHIR3:
7468c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
7478c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
7488c2ecf20Sopenharmony_ci		hw->isac.mode = hw->cfg.mode;
7498c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
7508c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
7518c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->cfg.mode;
7528c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
7538c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
7548c2ecf20Sopenharmony_ci		outb(0xff, (ulong)hw->cfg.start);
7558c2ecf20Sopenharmony_ci		mdelay(1);
7568c2ecf20Sopenharmony_ci		outb(0x00, (ulong)hw->cfg.start);
7578c2ecf20Sopenharmony_ci		mdelay(1);
7588c2ecf20Sopenharmony_ci		outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);
7598c2ecf20Sopenharmony_ci		break;
7608c2ecf20Sopenharmony_ci	case INF_QS1000:
7618c2ecf20Sopenharmony_ci	case INF_QS3000:
7628c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
7638c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
7648c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start;
7658c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->addr.start + 1;
7668c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7678c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = (u32)hw->addr.start;
7688c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = (u32)hw->addr.start + 1;
7698c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7708c2ecf20Sopenharmony_ci		break;
7718c2ecf20Sopenharmony_ci	case INF_NICCY:
7728c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
7738c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7748c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;
7758c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;
7768c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7778c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;
7788c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;
7798c2ecf20Sopenharmony_ci		break;
7808c2ecf20Sopenharmony_ci	case INF_SCT_1:
7818c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
7828c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
7838c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start;
7848c2ecf20Sopenharmony_ci		hw->isac.a.io.port = hw->isac.a.io.ale + 4;
7858c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7868c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = hw->isac.a.io.ale;
7878c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
7888c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7898c2ecf20Sopenharmony_ci		break;
7908c2ecf20Sopenharmony_ci	case INF_SCT_2:
7918c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
7928c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
7938c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;
7948c2ecf20Sopenharmony_ci		hw->isac.a.io.port = hw->isac.a.io.ale + 4;
7958c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
7968c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = hw->isac.a.io.ale;
7978c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
7988c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
7998c2ecf20Sopenharmony_ci		break;
8008c2ecf20Sopenharmony_ci	case INF_SCT_3:
8018c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
8028c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
8038c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;
8048c2ecf20Sopenharmony_ci		hw->isac.a.io.port = hw->isac.a.io.ale + 4;
8058c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
8068c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = hw->isac.a.io.ale;
8078c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
8088c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
8098c2ecf20Sopenharmony_ci		break;
8108c2ecf20Sopenharmony_ci	case INF_SCT_4:
8118c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
8128c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
8138c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;
8148c2ecf20Sopenharmony_ci		hw->isac.a.io.port = hw->isac.a.io.ale + 4;
8158c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
8168c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = hw->isac.a.io.ale;
8178c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
8188c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
8198c2ecf20Sopenharmony_ci		break;
8208c2ecf20Sopenharmony_ci	case INF_GAZEL_R685:
8218c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
8228c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
8238c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
8248c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->addr.start;
8258c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
8268c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
8278c2ecf20Sopenharmony_ci		break;
8288c2ecf20Sopenharmony_ci	case INF_GAZEL_R753:
8298c2ecf20Sopenharmony_ci		hw->ipac.type = IPAC_TYPE_IPAC;
8308c2ecf20Sopenharmony_ci		hw->ipac.isac.off = 0x80;
8318c2ecf20Sopenharmony_ci		hw->isac.mode = hw->addr.mode;
8328c2ecf20Sopenharmony_ci		hw->isac.a.io.ale = (u32)hw->addr.start;
8338c2ecf20Sopenharmony_ci		hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;
8348c2ecf20Sopenharmony_ci		hw->hscx.mode = hw->addr.mode;
8358c2ecf20Sopenharmony_ci		hw->hscx.a.io.ale = hw->isac.a.io.ale;
8368c2ecf20Sopenharmony_ci		hw->hscx.a.io.port = hw->isac.a.io.port;
8378c2ecf20Sopenharmony_ci		break;
8388c2ecf20Sopenharmony_ci	default:
8398c2ecf20Sopenharmony_ci		return -EINVAL;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci	switch (hw->isac.mode) {
8428c2ecf20Sopenharmony_ci	case AM_MEMIO:
8438c2ecf20Sopenharmony_ci		ASSIGN_FUNC_IPAC(MIO, hw->ipac);
8448c2ecf20Sopenharmony_ci		break;
8458c2ecf20Sopenharmony_ci	case AM_IND_IO:
8468c2ecf20Sopenharmony_ci		ASSIGN_FUNC_IPAC(IND, hw->ipac);
8478c2ecf20Sopenharmony_ci		break;
8488c2ecf20Sopenharmony_ci	case AM_IO:
8498c2ecf20Sopenharmony_ci		ASSIGN_FUNC_IPAC(IO, hw->ipac);
8508c2ecf20Sopenharmony_ci		break;
8518c2ecf20Sopenharmony_ci	default:
8528c2ecf20Sopenharmony_ci		return -EINVAL;
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci	return 0;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic void
8588c2ecf20Sopenharmony_cirelease_card(struct inf_hw *card) {
8598c2ecf20Sopenharmony_ci	ulong	flags;
8608c2ecf20Sopenharmony_ci	int	i;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
8638c2ecf20Sopenharmony_ci	disable_hwirq(card);
8648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
8658c2ecf20Sopenharmony_ci	card->ipac.isac.release(&card->ipac.isac);
8668c2ecf20Sopenharmony_ci	free_irq(card->irq, card);
8678c2ecf20Sopenharmony_ci	mISDN_unregister_device(&card->ipac.isac.dch.dev);
8688c2ecf20Sopenharmony_ci	release_io(card);
8698c2ecf20Sopenharmony_ci	write_lock_irqsave(&card_lock, flags);
8708c2ecf20Sopenharmony_ci	list_del(&card->list);
8718c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&card_lock, flags);
8728c2ecf20Sopenharmony_ci	switch (card->ci->typ) {
8738c2ecf20Sopenharmony_ci	case INF_SCT_2:
8748c2ecf20Sopenharmony_ci	case INF_SCT_3:
8758c2ecf20Sopenharmony_ci	case INF_SCT_4:
8768c2ecf20Sopenharmony_ci		break;
8778c2ecf20Sopenharmony_ci	case INF_SCT_1:
8788c2ecf20Sopenharmony_ci		for (i = 0; i < 3; i++) {
8798c2ecf20Sopenharmony_ci			if (card->sc[i])
8808c2ecf20Sopenharmony_ci				release_card(card->sc[i]);
8818c2ecf20Sopenharmony_ci			card->sc[i] = NULL;
8828c2ecf20Sopenharmony_ci		}
8838c2ecf20Sopenharmony_ci		fallthrough;
8848c2ecf20Sopenharmony_ci	default:
8858c2ecf20Sopenharmony_ci		pci_disable_device(card->pdev);
8868c2ecf20Sopenharmony_ci		pci_set_drvdata(card->pdev, NULL);
8878c2ecf20Sopenharmony_ci		break;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci	kfree(card);
8908c2ecf20Sopenharmony_ci	inf_cnt--;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistatic int
8948c2ecf20Sopenharmony_cisetup_instance(struct inf_hw *card)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	int err;
8978c2ecf20Sopenharmony_ci	ulong flags;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,
9008c2ecf20Sopenharmony_ci		 inf_cnt + 1);
9018c2ecf20Sopenharmony_ci	write_lock_irqsave(&card_lock, flags);
9028c2ecf20Sopenharmony_ci	list_add_tail(&card->list, &Cards);
9038c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&card_lock, flags);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	_set_debug(card);
9068c2ecf20Sopenharmony_ci	card->ipac.isac.name = card->name;
9078c2ecf20Sopenharmony_ci	card->ipac.name = card->name;
9088c2ecf20Sopenharmony_ci	card->ipac.owner = THIS_MODULE;
9098c2ecf20Sopenharmony_ci	spin_lock_init(&card->lock);
9108c2ecf20Sopenharmony_ci	card->ipac.isac.hwlock = &card->lock;
9118c2ecf20Sopenharmony_ci	card->ipac.hwlock = &card->lock;
9128c2ecf20Sopenharmony_ci	card->ipac.ctrl = (void *)&inf_ctrl;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	err = setup_io(card);
9158c2ecf20Sopenharmony_ci	if (err)
9168c2ecf20Sopenharmony_ci		goto error_setup;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	card->ipac.isac.dch.dev.Bprotocols =
9198c2ecf20Sopenharmony_ci		mISDNipac_init(&card->ipac, card);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (card->ipac.isac.dch.dev.Bprotocols == 0)
9228c2ecf20Sopenharmony_ci		goto error_setup;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	err = mISDN_register_device(&card->ipac.isac.dch.dev,
9258c2ecf20Sopenharmony_ci				    &card->pdev->dev, card->name);
9268c2ecf20Sopenharmony_ci	if (err)
9278c2ecf20Sopenharmony_ci		goto error;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	err = init_irq(card);
9308c2ecf20Sopenharmony_ci	if (!err)  {
9318c2ecf20Sopenharmony_ci		inf_cnt++;
9328c2ecf20Sopenharmony_ci		pr_notice("Infineon %d cards installed\n", inf_cnt);
9338c2ecf20Sopenharmony_ci		return 0;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci	mISDN_unregister_device(&card->ipac.isac.dch.dev);
9368c2ecf20Sopenharmony_cierror:
9378c2ecf20Sopenharmony_ci	card->ipac.release(&card->ipac);
9388c2ecf20Sopenharmony_cierror_setup:
9398c2ecf20Sopenharmony_ci	release_io(card);
9408c2ecf20Sopenharmony_ci	write_lock_irqsave(&card_lock, flags);
9418c2ecf20Sopenharmony_ci	list_del(&card->list);
9428c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&card_lock, flags);
9438c2ecf20Sopenharmony_ci	return err;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic const struct inf_cinfo inf_card_info[] = {
9478c2ecf20Sopenharmony_ci	{
9488c2ecf20Sopenharmony_ci		INF_DIVA20,
9498c2ecf20Sopenharmony_ci		"Dialogic Diva 2.0",
9508c2ecf20Sopenharmony_ci		"diva20",
9518c2ecf20Sopenharmony_ci		AM_IND_IO, AM_NONE, 2, 0,
9528c2ecf20Sopenharmony_ci		&diva_irq
9538c2ecf20Sopenharmony_ci	},
9548c2ecf20Sopenharmony_ci	{
9558c2ecf20Sopenharmony_ci		INF_DIVA20U,
9568c2ecf20Sopenharmony_ci		"Dialogic Diva 2.0U",
9578c2ecf20Sopenharmony_ci		"diva20U",
9588c2ecf20Sopenharmony_ci		AM_IND_IO, AM_NONE, 2, 0,
9598c2ecf20Sopenharmony_ci		&diva_irq
9608c2ecf20Sopenharmony_ci	},
9618c2ecf20Sopenharmony_ci	{
9628c2ecf20Sopenharmony_ci		INF_DIVA201,
9638c2ecf20Sopenharmony_ci		"Dialogic Diva 2.01",
9648c2ecf20Sopenharmony_ci		"diva201",
9658c2ecf20Sopenharmony_ci		AM_MEMIO, AM_MEMIO, 0, 1,
9668c2ecf20Sopenharmony_ci		&diva20x_irq
9678c2ecf20Sopenharmony_ci	},
9688c2ecf20Sopenharmony_ci	{
9698c2ecf20Sopenharmony_ci		INF_DIVA202,
9708c2ecf20Sopenharmony_ci		"Dialogic Diva 2.02",
9718c2ecf20Sopenharmony_ci		"diva202",
9728c2ecf20Sopenharmony_ci		AM_MEMIO, AM_MEMIO, 0, 1,
9738c2ecf20Sopenharmony_ci		&diva20x_irq
9748c2ecf20Sopenharmony_ci	},
9758c2ecf20Sopenharmony_ci	{
9768c2ecf20Sopenharmony_ci		INF_SPEEDWIN,
9778c2ecf20Sopenharmony_ci		"Sedlbauer SpeedWin PCI",
9788c2ecf20Sopenharmony_ci		"speedwin",
9798c2ecf20Sopenharmony_ci		AM_IND_IO, AM_NONE, 0, 0,
9808c2ecf20Sopenharmony_ci		&tiger_irq
9818c2ecf20Sopenharmony_ci	},
9828c2ecf20Sopenharmony_ci	{
9838c2ecf20Sopenharmony_ci		INF_SAPHIR3,
9848c2ecf20Sopenharmony_ci		"HST Saphir 3",
9858c2ecf20Sopenharmony_ci		"saphir",
9868c2ecf20Sopenharmony_ci		AM_IND_IO, AM_NONE, 0, 0,
9878c2ecf20Sopenharmony_ci		&tiger_irq
9888c2ecf20Sopenharmony_ci	},
9898c2ecf20Sopenharmony_ci	{
9908c2ecf20Sopenharmony_ci		INF_QS1000,
9918c2ecf20Sopenharmony_ci		"Develo Microlink PCI",
9928c2ecf20Sopenharmony_ci		"qs1000",
9938c2ecf20Sopenharmony_ci		AM_IO, AM_IND_IO, 1, 3,
9948c2ecf20Sopenharmony_ci		&elsa_irq
9958c2ecf20Sopenharmony_ci	},
9968c2ecf20Sopenharmony_ci	{
9978c2ecf20Sopenharmony_ci		INF_QS3000,
9988c2ecf20Sopenharmony_ci		"Develo QuickStep 3000",
9998c2ecf20Sopenharmony_ci		"qs3000",
10008c2ecf20Sopenharmony_ci		AM_IO, AM_IND_IO, 1, 3,
10018c2ecf20Sopenharmony_ci		&elsa_irq
10028c2ecf20Sopenharmony_ci	},
10038c2ecf20Sopenharmony_ci	{
10048c2ecf20Sopenharmony_ci		INF_NICCY,
10058c2ecf20Sopenharmony_ci		"Sagem NICCY",
10068c2ecf20Sopenharmony_ci		"niccy",
10078c2ecf20Sopenharmony_ci		AM_IO, AM_IND_IO, 0, 1,
10088c2ecf20Sopenharmony_ci		&niccy_irq
10098c2ecf20Sopenharmony_ci	},
10108c2ecf20Sopenharmony_ci	{
10118c2ecf20Sopenharmony_ci		INF_SCT_1,
10128c2ecf20Sopenharmony_ci		"SciTel Quadro",
10138c2ecf20Sopenharmony_ci		"p1_scitel",
10148c2ecf20Sopenharmony_ci		AM_IO, AM_IND_IO, 1, 5,
10158c2ecf20Sopenharmony_ci		&ipac_irq
10168c2ecf20Sopenharmony_ci	},
10178c2ecf20Sopenharmony_ci	{
10188c2ecf20Sopenharmony_ci		INF_SCT_2,
10198c2ecf20Sopenharmony_ci		"SciTel Quadro",
10208c2ecf20Sopenharmony_ci		"p2_scitel",
10218c2ecf20Sopenharmony_ci		AM_NONE, AM_IND_IO, 0, 4,
10228c2ecf20Sopenharmony_ci		&ipac_irq
10238c2ecf20Sopenharmony_ci	},
10248c2ecf20Sopenharmony_ci	{
10258c2ecf20Sopenharmony_ci		INF_SCT_3,
10268c2ecf20Sopenharmony_ci		"SciTel Quadro",
10278c2ecf20Sopenharmony_ci		"p3_scitel",
10288c2ecf20Sopenharmony_ci		AM_NONE, AM_IND_IO, 0, 3,
10298c2ecf20Sopenharmony_ci		&ipac_irq
10308c2ecf20Sopenharmony_ci	},
10318c2ecf20Sopenharmony_ci	{
10328c2ecf20Sopenharmony_ci		INF_SCT_4,
10338c2ecf20Sopenharmony_ci		"SciTel Quadro",
10348c2ecf20Sopenharmony_ci		"p4_scitel",
10358c2ecf20Sopenharmony_ci		AM_NONE, AM_IND_IO, 0, 2,
10368c2ecf20Sopenharmony_ci		&ipac_irq
10378c2ecf20Sopenharmony_ci	},
10388c2ecf20Sopenharmony_ci	{
10398c2ecf20Sopenharmony_ci		INF_GAZEL_R685,
10408c2ecf20Sopenharmony_ci		"Gazel R685",
10418c2ecf20Sopenharmony_ci		"gazel685",
10428c2ecf20Sopenharmony_ci		AM_IO, AM_IO, 1, 2,
10438c2ecf20Sopenharmony_ci		&gazel_irq
10448c2ecf20Sopenharmony_ci	},
10458c2ecf20Sopenharmony_ci	{
10468c2ecf20Sopenharmony_ci		INF_GAZEL_R753,
10478c2ecf20Sopenharmony_ci		"Gazel R753",
10488c2ecf20Sopenharmony_ci		"gazel753",
10498c2ecf20Sopenharmony_ci		AM_IO, AM_IND_IO, 1, 2,
10508c2ecf20Sopenharmony_ci		&ipac_irq
10518c2ecf20Sopenharmony_ci	},
10528c2ecf20Sopenharmony_ci	{
10538c2ecf20Sopenharmony_ci		INF_NONE,
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci};
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_cistatic const struct inf_cinfo *
10588c2ecf20Sopenharmony_ciget_card_info(enum inf_types typ)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	const struct inf_cinfo *ci = inf_card_info;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	while (ci->typ != INF_NONE) {
10638c2ecf20Sopenharmony_ci		if (ci->typ == typ)
10648c2ecf20Sopenharmony_ci			return ci;
10658c2ecf20Sopenharmony_ci		ci++;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci	return NULL;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int
10718c2ecf20Sopenharmony_ciinf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	int err = -ENOMEM;
10748c2ecf20Sopenharmony_ci	struct inf_hw *card;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
10778c2ecf20Sopenharmony_ci	if (!card) {
10788c2ecf20Sopenharmony_ci		pr_info("No memory for Infineon ISDN card\n");
10798c2ecf20Sopenharmony_ci		return err;
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci	card->pdev = pdev;
10828c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
10838c2ecf20Sopenharmony_ci	if (err) {
10848c2ecf20Sopenharmony_ci		kfree(card);
10858c2ecf20Sopenharmony_ci		return err;
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	card->ci = get_card_info(ent->driver_data);
10888c2ecf20Sopenharmony_ci	if (!card->ci) {
10898c2ecf20Sopenharmony_ci		pr_info("mISDN: do not have information about adapter at %s\n",
10908c2ecf20Sopenharmony_ci			pci_name(pdev));
10918c2ecf20Sopenharmony_ci		kfree(card);
10928c2ecf20Sopenharmony_ci		pci_disable_device(pdev);
10938c2ecf20Sopenharmony_ci		return -EINVAL;
10948c2ecf20Sopenharmony_ci	} else
10958c2ecf20Sopenharmony_ci		pr_notice("mISDN: found adapter %s at %s\n",
10968c2ecf20Sopenharmony_ci			  card->ci->full, pci_name(pdev));
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	card->irq = pdev->irq;
10998c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, card);
11008c2ecf20Sopenharmony_ci	err = setup_instance(card);
11018c2ecf20Sopenharmony_ci	if (err) {
11028c2ecf20Sopenharmony_ci		pci_disable_device(pdev);
11038c2ecf20Sopenharmony_ci		kfree(card);
11048c2ecf20Sopenharmony_ci		pci_set_drvdata(pdev, NULL);
11058c2ecf20Sopenharmony_ci	} else if (ent->driver_data == INF_SCT_1) {
11068c2ecf20Sopenharmony_ci		int i;
11078c2ecf20Sopenharmony_ci		struct inf_hw *sc;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		for (i = 1; i < 4; i++) {
11108c2ecf20Sopenharmony_ci			sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
11118c2ecf20Sopenharmony_ci			if (!sc) {
11128c2ecf20Sopenharmony_ci				release_card(card);
11138c2ecf20Sopenharmony_ci				pci_disable_device(pdev);
11148c2ecf20Sopenharmony_ci				return -ENOMEM;
11158c2ecf20Sopenharmony_ci			}
11168c2ecf20Sopenharmony_ci			sc->irq = card->irq;
11178c2ecf20Sopenharmony_ci			sc->pdev = card->pdev;
11188c2ecf20Sopenharmony_ci			sc->ci = card->ci + i;
11198c2ecf20Sopenharmony_ci			err = setup_instance(sc);
11208c2ecf20Sopenharmony_ci			if (err) {
11218c2ecf20Sopenharmony_ci				pci_disable_device(pdev);
11228c2ecf20Sopenharmony_ci				kfree(sc);
11238c2ecf20Sopenharmony_ci				release_card(card);
11248c2ecf20Sopenharmony_ci				break;
11258c2ecf20Sopenharmony_ci			} else
11268c2ecf20Sopenharmony_ci				card->sc[i - 1] = sc;
11278c2ecf20Sopenharmony_ci		}
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci	return err;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic void
11338c2ecf20Sopenharmony_ciinf_remove(struct pci_dev *pdev)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	struct inf_hw	*card = pci_get_drvdata(pdev);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	if (card)
11388c2ecf20Sopenharmony_ci		release_card(card);
11398c2ecf20Sopenharmony_ci	else
11408c2ecf20Sopenharmony_ci		pr_debug("%s: drvdata already removed\n", __func__);
11418c2ecf20Sopenharmony_ci}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_cistatic struct pci_driver infineon_driver = {
11448c2ecf20Sopenharmony_ci	.name = "ISDN Infineon pci",
11458c2ecf20Sopenharmony_ci	.probe = inf_probe,
11468c2ecf20Sopenharmony_ci	.remove = inf_remove,
11478c2ecf20Sopenharmony_ci	.id_table = infineon_ids,
11488c2ecf20Sopenharmony_ci};
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_cistatic int __init
11518c2ecf20Sopenharmony_ciinfineon_init(void)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	int err;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);
11568c2ecf20Sopenharmony_ci	err = pci_register_driver(&infineon_driver);
11578c2ecf20Sopenharmony_ci	return err;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistatic void __exit
11618c2ecf20Sopenharmony_ciinfineon_cleanup(void)
11628c2ecf20Sopenharmony_ci{
11638c2ecf20Sopenharmony_ci	pci_unregister_driver(&infineon_driver);
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cimodule_init(infineon_init);
11678c2ecf20Sopenharmony_cimodule_exit(infineon_cleanup);
1168