brintos

brintos / linux-shallow public Read only

0
0
Text · 26.7 KiB · 30876a0 Raw
1169 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * mISDNinfineon.c4 *		Support for cards based on following Infineon ISDN chipsets5 *		- ISAC + HSCX6 *		- IPAC and IPAC-X7 *		- ISAC-SX + HSCX8 *9 * Supported cards:10 *		- Dialogic Diva 2.011 *		- Dialogic Diva 2.0U12 *		- Dialogic Diva 2.0113 *		- Dialogic Diva 2.0214 *		- Sedlbauer Speedwin15 *		- HST Saphir316 *		- Develo (former ELSA) Microlink PCI (Quickstep 1000)17 *		- Develo (former ELSA) Quickstep 300018 *		- Berkom Scitel BRIX Quadro19 *		- Dr.Neuhaus (Sagem) Niccy20 *21 * Author       Karsten Keil <keil@isdn4linux.de>22 *23 * Copyright 2009  by Karsten Keil <keil@isdn4linux.de>24 */25 26#include <linux/interrupt.h>27#include <linux/module.h>28#include <linux/pci.h>29#include <linux/delay.h>30#include <linux/mISDNhw.h>31#include <linux/slab.h>32#include "ipac.h"33 34#define INFINEON_REV	"1.0"35 36static int inf_cnt;37static u32 debug;38static u32 irqloops = 4;39 40enum inf_types {41	INF_NONE,42	INF_DIVA20,43	INF_DIVA20U,44	INF_DIVA201,45	INF_DIVA202,46	INF_SPEEDWIN,47	INF_SAPHIR3,48	INF_QS1000,49	INF_QS3000,50	INF_NICCY,51	INF_SCT_1,52	INF_SCT_2,53	INF_SCT_3,54	INF_SCT_4,55	INF_GAZEL_R685,56	INF_GAZEL_R75357};58 59enum addr_mode {60	AM_NONE = 0,61	AM_IO,62	AM_MEMIO,63	AM_IND_IO,64};65 66struct inf_cinfo {67	enum inf_types	typ;68	const char	*full;69	const char	*name;70	enum addr_mode	cfg_mode;71	enum addr_mode	addr_mode;72	u8		cfg_bar;73	u8		addr_bar;74	void		*irqfunc;75};76 77struct _ioaddr {78	enum addr_mode	mode;79	union {80		void __iomem	*p;81		struct _ioport	io;82	} a;83};84 85struct _iohandle {86	enum addr_mode	mode;87	resource_size_t	size;88	resource_size_t	start;89	void __iomem	*p;90};91 92struct inf_hw {93	struct list_head	list;94	struct pci_dev		*pdev;95	const struct inf_cinfo	*ci;96	char			name[MISDN_MAX_IDLEN];97	u32			irq;98	u32			irqcnt;99	struct _iohandle	cfg;100	struct _iohandle	addr;101	struct _ioaddr		isac;102	struct _ioaddr		hscx;103	spinlock_t		lock;	/* HW access lock */104	struct ipac_hw		ipac;105	struct inf_hw		*sc[3];	/* slave cards */106};107 108 109#define PCI_SUBVENDOR_HST_SAPHIR3       0x52110#define PCI_SUBVENDOR_SEDLBAUER_PCI     0x53111#define PCI_SUB_ID_SEDLBAUER            0x01112 113static struct pci_device_id infineon_ids[] = {114	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },115	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },116	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },117	{ PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202), INF_DIVA202 },118	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,119	  PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,120	  INF_SPEEDWIN },121	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,122	  PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3 },123	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK), INF_QS1000 },124	{ PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000), INF_QS3000 },125	{ PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY), INF_NICCY },126	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,127	  PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,128	  INF_SCT_1 },129	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685), INF_GAZEL_R685 },130	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753), INF_GAZEL_R753 },131	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO), INF_GAZEL_R753 },132	{ PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC), INF_GAZEL_R753 },133	{ }134};135MODULE_DEVICE_TABLE(pci, infineon_ids);136 137/* PCI interface specific defines */138/* Diva 2.0/2.0U */139#define DIVA_HSCX_PORT		0x00140#define DIVA_HSCX_ALE		0x04141#define DIVA_ISAC_PORT		0x08142#define DIVA_ISAC_ALE		0x0C143#define DIVA_PCI_CTRL           0x10144 145/* DIVA_PCI_CTRL bits */146#define DIVA_IRQ_BIT		0x01147#define DIVA_RESET_BIT		0x08148#define DIVA_EEPROM_CLK		0x40149#define DIVA_LED_A		0x10150#define DIVA_LED_B		0x20151#define DIVA_IRQ_CLR		0x80152 153/* Diva 2.01/2.02 */154/* Siemens PITA */155#define PITA_ICR_REG		0x00156#define PITA_INT0_STATUS	0x02157 158#define PITA_MISC_REG		0x1c159#define PITA_PARA_SOFTRESET	0x01000000160#define PITA_SER_SOFTRESET	0x02000000161#define PITA_PARA_MPX_MODE	0x04000000162#define PITA_INT0_ENABLE	0x00020000163 164/* TIGER 100 Registers */165#define TIGER_RESET_ADDR	0x00166#define TIGER_EXTERN_RESET	0x01167#define TIGER_AUX_CTRL		0x02168#define TIGER_AUX_DATA		0x03169#define TIGER_AUX_IRQMASK	0x05170#define TIGER_AUX_STATUS	0x07171 172/* Tiger AUX BITs */173#define TIGER_IOMASK		0xdd	/* 1 and 5 are inputs */174#define TIGER_IRQ_BIT		0x02175 176#define TIGER_IPAC_ALE		0xC0177#define TIGER_IPAC_PORT		0xC8178 179/* ELSA (now Develo) PCI cards */180#define ELSA_IRQ_ADDR		0x4c181#define ELSA_IRQ_MASK		0x04182#define QS1000_IRQ_OFF		0x01183#define QS3000_IRQ_OFF		0x03184#define QS1000_IRQ_ON		0x41185#define QS3000_IRQ_ON		0x43186 187/* Dr Neuhaus/Sagem Niccy */188#define NICCY_ISAC_PORT		0x00189#define NICCY_HSCX_PORT		0x01190#define NICCY_ISAC_ALE		0x02191#define NICCY_HSCX_ALE		0x03192 193#define NICCY_IRQ_CTRL_REG	0x38194#define NICCY_IRQ_ENABLE	0x001f00195#define NICCY_IRQ_DISABLE	0xff0000196#define NICCY_IRQ_BIT		0x800000197 198 199/* Scitel PLX */200#define SCT_PLX_IRQ_ADDR	0x4c201#define SCT_PLX_RESET_ADDR	0x50202#define SCT_PLX_IRQ_ENABLE	0x41203#define SCT_PLX_RESET_BIT	0x04204 205/* Gazel */206#define	GAZEL_IPAC_DATA_PORT	0x04207/* Gazel PLX */208#define GAZEL_CNTRL		0x50209#define GAZEL_RESET		0x04210#define GAZEL_RESET_9050	0x40000000211#define GAZEL_INCSR		0x4C212#define GAZEL_ISAC_EN		0x08213#define GAZEL_INT_ISAC		0x20214#define GAZEL_HSCX_EN		0x01215#define GAZEL_INT_HSCX		0x04216#define GAZEL_PCI_EN		0x40217#define GAZEL_IPAC_EN		0x03218 219 220static LIST_HEAD(Cards);221static DEFINE_RWLOCK(card_lock); /* protect Cards */222 223static void224_set_debug(struct inf_hw *card)225{226	card->ipac.isac.dch.debug = debug;227	card->ipac.hscx[0].bch.debug = debug;228	card->ipac.hscx[1].bch.debug = debug;229}230 231static int232set_debug(const char *val, const struct kernel_param *kp)233{234	int ret;235	struct inf_hw *card;236 237	ret = param_set_uint(val, kp);238	if (!ret) {239		read_lock(&card_lock);240		list_for_each_entry(card, &Cards, list)241			_set_debug(card);242		read_unlock(&card_lock);243	}244	return ret;245}246 247MODULE_AUTHOR("Karsten Keil");248MODULE_DESCRIPTION("mISDN driver for cards based on Infineon ISDN chipsets");249MODULE_LICENSE("GPL v2");250MODULE_VERSION(INFINEON_REV);251module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);252MODULE_PARM_DESC(debug, "infineon debug mask");253module_param(irqloops, uint, S_IRUGO | S_IWUSR);254MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");255 256/* Interface functions */257 258IOFUNC_IO(ISAC, inf_hw, isac.a.io)259IOFUNC_IO(IPAC, inf_hw, hscx.a.io)260IOFUNC_IND(ISAC, inf_hw, isac.a.io)261IOFUNC_IND(IPAC, inf_hw, hscx.a.io)262IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)263IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)264 265static irqreturn_t266diva_irq(int intno, void *dev_id)267{268	struct inf_hw *hw = dev_id;269	u8 val;270 271	spin_lock(&hw->lock);272	val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);273	if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */274		spin_unlock(&hw->lock);275		return IRQ_NONE; /* shared */276	}277	hw->irqcnt++;278	mISDNipac_irq(&hw->ipac, irqloops);279	spin_unlock(&hw->lock);280	return IRQ_HANDLED;281}282 283static irqreturn_t284diva20x_irq(int intno, void *dev_id)285{286	struct inf_hw *hw = dev_id;287	u8 val;288 289	spin_lock(&hw->lock);290	val = readb(hw->cfg.p);291	if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */292		spin_unlock(&hw->lock);293		return IRQ_NONE; /* shared */294	}295	hw->irqcnt++;296	mISDNipac_irq(&hw->ipac, irqloops);297	writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */298	spin_unlock(&hw->lock);299	return IRQ_HANDLED;300}301 302static irqreturn_t303tiger_irq(int intno, void *dev_id)304{305	struct inf_hw *hw = dev_id;306	u8 val;307 308	spin_lock(&hw->lock);309	val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);310	if (val & TIGER_IRQ_BIT) { /* for us or shared ? */311		spin_unlock(&hw->lock);312		return IRQ_NONE; /* shared */313	}314	hw->irqcnt++;315	mISDNipac_irq(&hw->ipac, irqloops);316	spin_unlock(&hw->lock);317	return IRQ_HANDLED;318}319 320static irqreturn_t321elsa_irq(int intno, void *dev_id)322{323	struct inf_hw *hw = dev_id;324	u8 val;325 326	spin_lock(&hw->lock);327	val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);328	if (!(val & ELSA_IRQ_MASK)) {329		spin_unlock(&hw->lock);330		return IRQ_NONE; /* shared */331	}332	hw->irqcnt++;333	mISDNipac_irq(&hw->ipac, irqloops);334	spin_unlock(&hw->lock);335	return IRQ_HANDLED;336}337 338static irqreturn_t339niccy_irq(int intno, void *dev_id)340{341	struct inf_hw *hw = dev_id;342	u32 val;343 344	spin_lock(&hw->lock);345	val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);346	if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */347		spin_unlock(&hw->lock);348		return IRQ_NONE; /* shared */349	}350	outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);351	hw->irqcnt++;352	mISDNipac_irq(&hw->ipac, irqloops);353	spin_unlock(&hw->lock);354	return IRQ_HANDLED;355}356 357static irqreturn_t358gazel_irq(int intno, void *dev_id)359{360	struct inf_hw *hw = dev_id;361	irqreturn_t ret;362 363	spin_lock(&hw->lock);364	ret = mISDNipac_irq(&hw->ipac, irqloops);365	spin_unlock(&hw->lock);366	return ret;367}368 369static irqreturn_t370ipac_irq(int intno, void *dev_id)371{372	struct inf_hw *hw = dev_id;373	u8 val;374 375	spin_lock(&hw->lock);376	val = hw->ipac.read_reg(hw, IPAC_ISTA);377	if (!(val & 0x3f)) {378		spin_unlock(&hw->lock);379		return IRQ_NONE; /* shared */380	}381	hw->irqcnt++;382	mISDNipac_irq(&hw->ipac, irqloops);383	spin_unlock(&hw->lock);384	return IRQ_HANDLED;385}386 387static void388enable_hwirq(struct inf_hw *hw)389{390	u16 w;391	u32 val;392 393	switch (hw->ci->typ) {394	case INF_DIVA201:395	case INF_DIVA202:396		writel(PITA_INT0_ENABLE, hw->cfg.p);397		break;398	case INF_SPEEDWIN:399	case INF_SAPHIR3:400		outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);401		break;402	case INF_QS1000:403		outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);404		break;405	case INF_QS3000:406		outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);407		break;408	case INF_NICCY:409		val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);410		val |= NICCY_IRQ_ENABLE;411		outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);412		break;413	case INF_SCT_1:414		w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);415		w |= SCT_PLX_IRQ_ENABLE;416		outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);417		break;418	case INF_GAZEL_R685:419		outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,420		     (u32)hw->cfg.start + GAZEL_INCSR);421		break;422	case INF_GAZEL_R753:423		outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,424		     (u32)hw->cfg.start + GAZEL_INCSR);425		break;426	default:427		break;428	}429}430 431static void432disable_hwirq(struct inf_hw *hw)433{434	u16 w;435	u32 val;436 437	switch (hw->ci->typ) {438	case INF_DIVA201:439	case INF_DIVA202:440		writel(0, hw->cfg.p);441		break;442	case INF_SPEEDWIN:443	case INF_SAPHIR3:444		outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);445		break;446	case INF_QS1000:447		outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);448		break;449	case INF_QS3000:450		outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);451		break;452	case INF_NICCY:453		val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);454		val &= NICCY_IRQ_DISABLE;455		outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);456		break;457	case INF_SCT_1:458		w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);459		w &= (~SCT_PLX_IRQ_ENABLE);460		outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);461		break;462	case INF_GAZEL_R685:463	case INF_GAZEL_R753:464		outb(0, (u32)hw->cfg.start + GAZEL_INCSR);465		break;466	default:467		break;468	}469}470 471static void472ipac_chip_reset(struct inf_hw *hw)473{474	hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);475	mdelay(5);476	hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);477	mdelay(5);478	hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);479	hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);480}481 482static void483reset_inf(struct inf_hw *hw)484{485	u16 w;486	u32 val;487 488	if (debug & DEBUG_HW)489		pr_notice("%s: resetting card\n", hw->name);490	switch (hw->ci->typ) {491	case INF_DIVA20:492	case INF_DIVA20U:493		outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);494		mdelay(10);495		outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);496		mdelay(10);497		/* Workaround PCI9060 */498		outb(9, (u32)hw->cfg.start + 0x69);499		outb(DIVA_RESET_BIT | DIVA_LED_A,500		     (u32)hw->cfg.start + DIVA_PCI_CTRL);501		break;502	case INF_DIVA201:503		writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,504		       hw->cfg.p + PITA_MISC_REG);505		mdelay(1);506		writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);507		mdelay(10);508		break;509	case INF_DIVA202:510		writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,511		       hw->cfg.p + PITA_MISC_REG);512		mdelay(1);513		writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,514		       hw->cfg.p + PITA_MISC_REG);515		mdelay(10);516		break;517	case INF_SPEEDWIN:518	case INF_SAPHIR3:519		ipac_chip_reset(hw);520		hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);521		hw->ipac.write_reg(hw, IPAC_AOE, 0x00);522		hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);523		break;524	case INF_QS1000:525	case INF_QS3000:526		ipac_chip_reset(hw);527		hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);528		hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);529		hw->ipac.write_reg(hw, IPAC_ATX, 0xff);530		break;531	case INF_NICCY:532		break;533	case INF_SCT_1:534		w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);535		w &= (~SCT_PLX_RESET_BIT);536		outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);537		mdelay(10);538		w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);539		w |= SCT_PLX_RESET_BIT;540		outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);541		mdelay(10);542		break;543	case INF_GAZEL_R685:544		val = inl((u32)hw->cfg.start + GAZEL_CNTRL);545		val |= (GAZEL_RESET_9050 + GAZEL_RESET);546		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);547		val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);548		mdelay(4);549		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);550		mdelay(10);551		hw->ipac.isac.adf2 = 0x87;552		hw->ipac.hscx[0].slot = 0x1f;553		hw->ipac.hscx[1].slot = 0x23;554		break;555	case INF_GAZEL_R753:556		val = inl((u32)hw->cfg.start + GAZEL_CNTRL);557		val |= (GAZEL_RESET_9050 + GAZEL_RESET);558		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);559		val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);560		mdelay(4);561		outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);562		mdelay(10);563		ipac_chip_reset(hw);564		hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);565		hw->ipac.write_reg(hw, IPAC_AOE, 0x00);566		hw->ipac.conf = 0x01; /* IOM off */567		break;568	default:569		return;570	}571	enable_hwirq(hw);572}573 574static int575inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)576{577	int ret = 0;578 579	switch (cmd) {580	case HW_RESET_REQ:581		reset_inf(hw);582		break;583	default:584		pr_info("%s: %s unknown command %x %lx\n",585			hw->name, __func__, cmd, arg);586		ret = -EINVAL;587		break;588	}589	return ret;590}591 592static int593init_irq(struct inf_hw *hw)594{595	int	ret, cnt = 3;596	u_long	flags;597 598	if (!hw->ci->irqfunc)599		return -EINVAL;600	ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);601	if (ret) {602		pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);603		return ret;604	}605	while (cnt--) {606		spin_lock_irqsave(&hw->lock, flags);607		reset_inf(hw);608		ret = hw->ipac.init(&hw->ipac);609		if (ret) {610			spin_unlock_irqrestore(&hw->lock, flags);611			pr_info("%s: ISAC init failed with %d\n",612				hw->name, ret);613			break;614		}615		spin_unlock_irqrestore(&hw->lock, flags);616		msleep_interruptible(10);617		if (debug & DEBUG_HW)618			pr_notice("%s: IRQ %d count %d\n", hw->name,619				  hw->irq, hw->irqcnt);620		if (!hw->irqcnt) {621			pr_info("%s: IRQ(%d) got no requests during init %d\n",622				hw->name, hw->irq, 3 - cnt);623		} else624			return 0;625	}626	free_irq(hw->irq, hw);627	return -EIO;628}629 630static void631release_io(struct inf_hw *hw)632{633	if (hw->cfg.mode) {634		if (hw->cfg.mode == AM_MEMIO) {635			release_mem_region(hw->cfg.start, hw->cfg.size);636			if (hw->cfg.p)637				iounmap(hw->cfg.p);638		} else639			release_region(hw->cfg.start, hw->cfg.size);640		hw->cfg.mode = AM_NONE;641	}642	if (hw->addr.mode) {643		if (hw->addr.mode == AM_MEMIO) {644			release_mem_region(hw->addr.start, hw->addr.size);645			if (hw->addr.p)646				iounmap(hw->addr.p);647		} else648			release_region(hw->addr.start, hw->addr.size);649		hw->addr.mode = AM_NONE;650	}651}652 653static int654setup_io(struct inf_hw *hw)655{656	int err = 0;657 658	if (hw->ci->cfg_mode) {659		hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);660		hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);661		if (hw->ci->cfg_mode == AM_MEMIO) {662			if (!request_mem_region(hw->cfg.start, hw->cfg.size,663						hw->name))664				err = -EBUSY;665		} else {666			if (!request_region(hw->cfg.start, hw->cfg.size,667					    hw->name))668				err = -EBUSY;669		}670		if (err) {671			pr_info("mISDN: %s config port %lx (%lu bytes)"672				"already in use\n", hw->name,673				(ulong)hw->cfg.start, (ulong)hw->cfg.size);674			return err;675		}676		hw->cfg.mode = hw->ci->cfg_mode;677		if (hw->ci->cfg_mode == AM_MEMIO) {678			hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);679			if (!hw->cfg.p)680				return -ENOMEM;681		}682		if (debug & DEBUG_HW)683			pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",684				  hw->name, (ulong)hw->cfg.start,685				  (ulong)hw->cfg.size, hw->ci->cfg_mode);686 687	}688	if (hw->ci->addr_mode) {689		hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);690		hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);691		if (hw->ci->addr_mode == AM_MEMIO) {692			if (!request_mem_region(hw->addr.start, hw->addr.size,693						hw->name))694				err = -EBUSY;695		} else {696			if (!request_region(hw->addr.start, hw->addr.size,697					    hw->name))698				err = -EBUSY;699		}700		if (err) {701			pr_info("mISDN: %s address port %lx (%lu bytes)"702				"already in use\n", hw->name,703				(ulong)hw->addr.start, (ulong)hw->addr.size);704			return err;705		}706		hw->addr.mode = hw->ci->addr_mode;707		if (hw->ci->addr_mode == AM_MEMIO) {708			hw->addr.p = ioremap(hw->addr.start, hw->addr.size);709			if (!hw->addr.p)710				return -ENOMEM;711		}712		if (debug & DEBUG_HW)713			pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",714				  hw->name, (ulong)hw->addr.start,715				  (ulong)hw->addr.size, hw->ci->addr_mode);716 717	}718 719	switch (hw->ci->typ) {720	case INF_DIVA20:721	case INF_DIVA20U:722		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;723		hw->isac.mode = hw->cfg.mode;724		hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;725		hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;726		hw->hscx.mode = hw->cfg.mode;727		hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;728		hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;729		break;730	case INF_DIVA201:731		hw->ipac.type = IPAC_TYPE_IPAC;732		hw->ipac.isac.off = 0x80;733		hw->isac.mode = hw->addr.mode;734		hw->isac.a.p = hw->addr.p;735		hw->hscx.mode = hw->addr.mode;736		hw->hscx.a.p = hw->addr.p;737		break;738	case INF_DIVA202:739		hw->ipac.type = IPAC_TYPE_IPACX;740		hw->isac.mode = hw->addr.mode;741		hw->isac.a.p = hw->addr.p;742		hw->hscx.mode = hw->addr.mode;743		hw->hscx.a.p = hw->addr.p;744		break;745	case INF_SPEEDWIN:746	case INF_SAPHIR3:747		hw->ipac.type = IPAC_TYPE_IPAC;748		hw->ipac.isac.off = 0x80;749		hw->isac.mode = hw->cfg.mode;750		hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;751		hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;752		hw->hscx.mode = hw->cfg.mode;753		hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;754		hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;755		outb(0xff, (ulong)hw->cfg.start);756		mdelay(1);757		outb(0x00, (ulong)hw->cfg.start);758		mdelay(1);759		outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);760		break;761	case INF_QS1000:762	case INF_QS3000:763		hw->ipac.type = IPAC_TYPE_IPAC;764		hw->ipac.isac.off = 0x80;765		hw->isac.a.io.ale = (u32)hw->addr.start;766		hw->isac.a.io.port = (u32)hw->addr.start + 1;767		hw->isac.mode = hw->addr.mode;768		hw->hscx.a.io.ale = (u32)hw->addr.start;769		hw->hscx.a.io.port = (u32)hw->addr.start + 1;770		hw->hscx.mode = hw->addr.mode;771		break;772	case INF_NICCY:773		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;774		hw->isac.mode = hw->addr.mode;775		hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;776		hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;777		hw->hscx.mode = hw->addr.mode;778		hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;779		hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;780		break;781	case INF_SCT_1:782		hw->ipac.type = IPAC_TYPE_IPAC;783		hw->ipac.isac.off = 0x80;784		hw->isac.a.io.ale = (u32)hw->addr.start;785		hw->isac.a.io.port = hw->isac.a.io.ale + 4;786		hw->isac.mode = hw->addr.mode;787		hw->hscx.a.io.ale = hw->isac.a.io.ale;788		hw->hscx.a.io.port = hw->isac.a.io.port;789		hw->hscx.mode = hw->addr.mode;790		break;791	case INF_SCT_2:792		hw->ipac.type = IPAC_TYPE_IPAC;793		hw->ipac.isac.off = 0x80;794		hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;795		hw->isac.a.io.port = hw->isac.a.io.ale + 4;796		hw->isac.mode = hw->addr.mode;797		hw->hscx.a.io.ale = hw->isac.a.io.ale;798		hw->hscx.a.io.port = hw->isac.a.io.port;799		hw->hscx.mode = hw->addr.mode;800		break;801	case INF_SCT_3:802		hw->ipac.type = IPAC_TYPE_IPAC;803		hw->ipac.isac.off = 0x80;804		hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;805		hw->isac.a.io.port = hw->isac.a.io.ale + 4;806		hw->isac.mode = hw->addr.mode;807		hw->hscx.a.io.ale = hw->isac.a.io.ale;808		hw->hscx.a.io.port = hw->isac.a.io.port;809		hw->hscx.mode = hw->addr.mode;810		break;811	case INF_SCT_4:812		hw->ipac.type = IPAC_TYPE_IPAC;813		hw->ipac.isac.off = 0x80;814		hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;815		hw->isac.a.io.port = hw->isac.a.io.ale + 4;816		hw->isac.mode = hw->addr.mode;817		hw->hscx.a.io.ale = hw->isac.a.io.ale;818		hw->hscx.a.io.port = hw->isac.a.io.port;819		hw->hscx.mode = hw->addr.mode;820		break;821	case INF_GAZEL_R685:822		hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;823		hw->ipac.isac.off = 0x80;824		hw->isac.mode = hw->addr.mode;825		hw->isac.a.io.port = (u32)hw->addr.start;826		hw->hscx.mode = hw->addr.mode;827		hw->hscx.a.io.port = hw->isac.a.io.port;828		break;829	case INF_GAZEL_R753:830		hw->ipac.type = IPAC_TYPE_IPAC;831		hw->ipac.isac.off = 0x80;832		hw->isac.mode = hw->addr.mode;833		hw->isac.a.io.ale = (u32)hw->addr.start;834		hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;835		hw->hscx.mode = hw->addr.mode;836		hw->hscx.a.io.ale = hw->isac.a.io.ale;837		hw->hscx.a.io.port = hw->isac.a.io.port;838		break;839	default:840		return -EINVAL;841	}842	switch (hw->isac.mode) {843	case AM_MEMIO:844		ASSIGN_FUNC_IPAC(MIO, hw->ipac);845		break;846	case AM_IND_IO:847		ASSIGN_FUNC_IPAC(IND, hw->ipac);848		break;849	case AM_IO:850		ASSIGN_FUNC_IPAC(IO, hw->ipac);851		break;852	default:853		return -EINVAL;854	}855	return 0;856}857 858static void859release_card(struct inf_hw *card) {860	ulong	flags;861	int	i;862 863	spin_lock_irqsave(&card->lock, flags);864	disable_hwirq(card);865	spin_unlock_irqrestore(&card->lock, flags);866	card->ipac.isac.release(&card->ipac.isac);867	free_irq(card->irq, card);868	mISDN_unregister_device(&card->ipac.isac.dch.dev);869	release_io(card);870	write_lock_irqsave(&card_lock, flags);871	list_del(&card->list);872	write_unlock_irqrestore(&card_lock, flags);873	switch (card->ci->typ) {874	case INF_SCT_2:875	case INF_SCT_3:876	case INF_SCT_4:877		break;878	case INF_SCT_1:879		for (i = 0; i < 3; i++) {880			if (card->sc[i])881				release_card(card->sc[i]);882			card->sc[i] = NULL;883		}884		fallthrough;885	default:886		pci_disable_device(card->pdev);887		pci_set_drvdata(card->pdev, NULL);888		break;889	}890	kfree(card);891	inf_cnt--;892}893 894static int895setup_instance(struct inf_hw *card)896{897	int err;898	ulong flags;899 900	snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,901		 inf_cnt + 1);902	write_lock_irqsave(&card_lock, flags);903	list_add_tail(&card->list, &Cards);904	write_unlock_irqrestore(&card_lock, flags);905 906	_set_debug(card);907	card->ipac.isac.name = card->name;908	card->ipac.name = card->name;909	card->ipac.owner = THIS_MODULE;910	spin_lock_init(&card->lock);911	card->ipac.isac.hwlock = &card->lock;912	card->ipac.hwlock = &card->lock;913	card->ipac.ctrl = (void *)&inf_ctrl;914 915	err = setup_io(card);916	if (err)917		goto error_setup;918 919	card->ipac.isac.dch.dev.Bprotocols =920		mISDNipac_init(&card->ipac, card);921 922	if (card->ipac.isac.dch.dev.Bprotocols == 0)923		goto error_setup;924 925	err = mISDN_register_device(&card->ipac.isac.dch.dev,926				    &card->pdev->dev, card->name);927	if (err)928		goto error;929 930	err = init_irq(card);931	if (!err)  {932		inf_cnt++;933		pr_notice("Infineon %d cards installed\n", inf_cnt);934		return 0;935	}936	mISDN_unregister_device(&card->ipac.isac.dch.dev);937error:938	card->ipac.release(&card->ipac);939error_setup:940	release_io(card);941	write_lock_irqsave(&card_lock, flags);942	list_del(&card->list);943	write_unlock_irqrestore(&card_lock, flags);944	return err;945}946 947static const struct inf_cinfo inf_card_info[] = {948	{949		INF_DIVA20,950		"Dialogic Diva 2.0",951		"diva20",952		AM_IND_IO, AM_NONE, 2, 0,953		&diva_irq954	},955	{956		INF_DIVA20U,957		"Dialogic Diva 2.0U",958		"diva20U",959		AM_IND_IO, AM_NONE, 2, 0,960		&diva_irq961	},962	{963		INF_DIVA201,964		"Dialogic Diva 2.01",965		"diva201",966		AM_MEMIO, AM_MEMIO, 0, 1,967		&diva20x_irq968	},969	{970		INF_DIVA202,971		"Dialogic Diva 2.02",972		"diva202",973		AM_MEMIO, AM_MEMIO, 0, 1,974		&diva20x_irq975	},976	{977		INF_SPEEDWIN,978		"Sedlbauer SpeedWin PCI",979		"speedwin",980		AM_IND_IO, AM_NONE, 0, 0,981		&tiger_irq982	},983	{984		INF_SAPHIR3,985		"HST Saphir 3",986		"saphir",987		AM_IND_IO, AM_NONE, 0, 0,988		&tiger_irq989	},990	{991		INF_QS1000,992		"Develo Microlink PCI",993		"qs1000",994		AM_IO, AM_IND_IO, 1, 3,995		&elsa_irq996	},997	{998		INF_QS3000,999		"Develo QuickStep 3000",1000		"qs3000",1001		AM_IO, AM_IND_IO, 1, 3,1002		&elsa_irq1003	},1004	{1005		INF_NICCY,1006		"Sagem NICCY",1007		"niccy",1008		AM_IO, AM_IND_IO, 0, 1,1009		&niccy_irq1010	},1011	{1012		INF_SCT_1,1013		"SciTel Quadro",1014		"p1_scitel",1015		AM_IO, AM_IND_IO, 1, 5,1016		&ipac_irq1017	},1018	{1019		INF_SCT_2,1020		"SciTel Quadro",1021		"p2_scitel",1022		AM_NONE, AM_IND_IO, 0, 4,1023		&ipac_irq1024	},1025	{1026		INF_SCT_3,1027		"SciTel Quadro",1028		"p3_scitel",1029		AM_NONE, AM_IND_IO, 0, 3,1030		&ipac_irq1031	},1032	{1033		INF_SCT_4,1034		"SciTel Quadro",1035		"p4_scitel",1036		AM_NONE, AM_IND_IO, 0, 2,1037		&ipac_irq1038	},1039	{1040		INF_GAZEL_R685,1041		"Gazel R685",1042		"gazel685",1043		AM_IO, AM_IO, 1, 2,1044		&gazel_irq1045	},1046	{1047		INF_GAZEL_R753,1048		"Gazel R753",1049		"gazel753",1050		AM_IO, AM_IND_IO, 1, 2,1051		&ipac_irq1052	},1053	{1054		INF_NONE,1055	}1056};1057 1058static const struct inf_cinfo *1059get_card_info(enum inf_types typ)1060{1061	const struct inf_cinfo *ci = inf_card_info;1062 1063	while (ci->typ != INF_NONE) {1064		if (ci->typ == typ)1065			return ci;1066		ci++;1067	}1068	return NULL;1069}1070 1071static int1072inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)1073{1074	int err = -ENOMEM;1075	struct inf_hw *card;1076 1077	card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1078	if (!card) {1079		pr_info("No memory for Infineon ISDN card\n");1080		return err;1081	}1082	card->pdev = pdev;1083	err = pci_enable_device(pdev);1084	if (err) {1085		kfree(card);1086		return err;1087	}1088	card->ci = get_card_info(ent->driver_data);1089	if (!card->ci) {1090		pr_info("mISDN: do not have information about adapter at %s\n",1091			pci_name(pdev));1092		kfree(card);1093		pci_disable_device(pdev);1094		return -EINVAL;1095	} else1096		pr_notice("mISDN: found adapter %s at %s\n",1097			  card->ci->full, pci_name(pdev));1098 1099	card->irq = pdev->irq;1100	pci_set_drvdata(pdev, card);1101	err = setup_instance(card);1102	if (err) {1103		pci_disable_device(pdev);1104		kfree(card);1105		pci_set_drvdata(pdev, NULL);1106	} else if (ent->driver_data == INF_SCT_1) {1107		int i;1108		struct inf_hw *sc;1109 1110		for (i = 1; i < 4; i++) {1111			sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);1112			if (!sc) {1113				release_card(card);1114				pci_disable_device(pdev);1115				return -ENOMEM;1116			}1117			sc->irq = card->irq;1118			sc->pdev = card->pdev;1119			sc->ci = card->ci + i;1120			err = setup_instance(sc);1121			if (err) {1122				pci_disable_device(pdev);1123				kfree(sc);1124				release_card(card);1125				break;1126			} else1127				card->sc[i - 1] = sc;1128		}1129	}1130	return err;1131}1132 1133static void1134inf_remove(struct pci_dev *pdev)1135{1136	struct inf_hw	*card = pci_get_drvdata(pdev);1137 1138	if (card)1139		release_card(card);1140	else1141		pr_debug("%s: drvdata already removed\n", __func__);1142}1143 1144static struct pci_driver infineon_driver = {1145	.name = "ISDN Infineon pci",1146	.probe = inf_probe,1147	.remove = inf_remove,1148	.id_table = infineon_ids,1149};1150 1151static int __init1152infineon_init(void)1153{1154	int err;1155 1156	pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);1157	err = pci_register_driver(&infineon_driver);1158	return err;1159}1160 1161static void __exit1162infineon_cleanup(void)1163{1164	pci_unregister_driver(&infineon_driver);1165}1166 1167module_init(infineon_init);1168module_exit(infineon_cleanup);1169