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