18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * speedfax.c low level stuff for Sedlbauer Speedfax+ cards 48c2ecf20Sopenharmony_ci * based on the ISAR DSP 58c2ecf20Sopenharmony_ci * Thanks to Sedlbauer AG for informations and HW 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author Karsten Keil <keil@isdn4linux.de> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 188c2ecf20Sopenharmony_ci#include <linux/firmware.h> 198c2ecf20Sopenharmony_ci#include "ipac.h" 208c2ecf20Sopenharmony_ci#include "isar.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SPEEDFAX_REV "2.0" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 258c2ecf20Sopenharmony_ci#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 268c2ecf20Sopenharmony_ci#define PCI_SUB_ID_SEDLBAUER 0x01 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SFAX_PCI_ADDR 0xc8 298c2ecf20Sopenharmony_ci#define SFAX_PCI_ISAC 0xd0 308c2ecf20Sopenharmony_ci#define SFAX_PCI_ISAR 0xe0 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* TIGER 100 Registers */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define TIGER_RESET_ADDR 0x00 358c2ecf20Sopenharmony_ci#define TIGER_EXTERN_RESET_ON 0x01 368c2ecf20Sopenharmony_ci#define TIGER_EXTERN_RESET_OFF 0x00 378c2ecf20Sopenharmony_ci#define TIGER_AUX_CTRL 0x02 388c2ecf20Sopenharmony_ci#define TIGER_AUX_DATA 0x03 398c2ecf20Sopenharmony_ci#define TIGER_AUX_IRQMASK 0x05 408c2ecf20Sopenharmony_ci#define TIGER_AUX_STATUS 0x07 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Tiger AUX BITs */ 438c2ecf20Sopenharmony_ci#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ 448c2ecf20Sopenharmony_ci#define SFAX_ISAR_RESET_BIT_OFF 0x00 458c2ecf20Sopenharmony_ci#define SFAX_ISAR_RESET_BIT_ON 0x01 468c2ecf20Sopenharmony_ci#define SFAX_TIGER_IRQ_BIT 0x02 478c2ecf20Sopenharmony_ci#define SFAX_LED1_BIT 0x08 488c2ecf20Sopenharmony_ci#define SFAX_LED2_BIT 0x10 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) 518c2ecf20Sopenharmony_ci#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int sfax_cnt; 548c2ecf20Sopenharmony_cistatic u32 debug; 558c2ecf20Sopenharmony_cistatic u32 irqloops = 4; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct sfax_hw { 588c2ecf20Sopenharmony_ci struct list_head list; 598c2ecf20Sopenharmony_ci struct pci_dev *pdev; 608c2ecf20Sopenharmony_ci char name[MISDN_MAX_IDLEN]; 618c2ecf20Sopenharmony_ci u32 irq; 628c2ecf20Sopenharmony_ci u32 irqcnt; 638c2ecf20Sopenharmony_ci u32 cfg; 648c2ecf20Sopenharmony_ci struct _ioport p_isac; 658c2ecf20Sopenharmony_ci struct _ioport p_isar; 668c2ecf20Sopenharmony_ci u8 aux_data; 678c2ecf20Sopenharmony_ci spinlock_t lock; /* HW access lock */ 688c2ecf20Sopenharmony_ci struct isac_hw isac; 698c2ecf20Sopenharmony_ci struct isar_hw isar; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic LIST_HEAD(Cards); 738c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(card_lock); /* protect Cards */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void 768c2ecf20Sopenharmony_ci_set_debug(struct sfax_hw *card) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci card->isac.dch.debug = debug; 798c2ecf20Sopenharmony_ci card->isar.ch[0].bch.debug = debug; 808c2ecf20Sopenharmony_ci card->isar.ch[1].bch.debug = debug; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int 848c2ecf20Sopenharmony_ciset_debug(const char *val, const struct kernel_param *kp) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci int ret; 878c2ecf20Sopenharmony_ci struct sfax_hw *card; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret = param_set_uint(val, kp); 908c2ecf20Sopenharmony_ci if (!ret) { 918c2ecf20Sopenharmony_ci read_lock(&card_lock); 928c2ecf20Sopenharmony_ci list_for_each_entry(card, &Cards, list) 938c2ecf20Sopenharmony_ci _set_debug(card); 948c2ecf20Sopenharmony_ci read_unlock(&card_lock); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 1008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1018c2ecf20Sopenharmony_ciMODULE_VERSION(SPEEDFAX_REV); 1028c2ecf20Sopenharmony_ciMODULE_FIRMWARE("isdn/ISAR.BIN"); 1038c2ecf20Sopenharmony_cimodule_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); 1048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Speedfax debug mask"); 1058c2ecf20Sopenharmony_cimodule_param(irqloops, uint, S_IRUGO | S_IWUSR); 1068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciIOFUNC_IND(ISAC, sfax_hw, p_isac) 1098c2ecf20Sopenharmony_ciIOFUNC_IND(ISAR, sfax_hw, p_isar) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic irqreturn_t 1128c2ecf20Sopenharmony_cispeedfax_irq(int intno, void *dev_id) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct sfax_hw *sf = dev_id; 1158c2ecf20Sopenharmony_ci u8 val; 1168c2ecf20Sopenharmony_ci int cnt = irqloops; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci spin_lock(&sf->lock); 1198c2ecf20Sopenharmony_ci val = inb(sf->cfg + TIGER_AUX_STATUS); 1208c2ecf20Sopenharmony_ci if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ 1218c2ecf20Sopenharmony_ci spin_unlock(&sf->lock); 1228c2ecf20Sopenharmony_ci return IRQ_NONE; /* shared */ 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci sf->irqcnt++; 1258c2ecf20Sopenharmony_ci val = ReadISAR_IND(sf, ISAR_IRQBIT); 1268c2ecf20Sopenharmony_ciStart_ISAR: 1278c2ecf20Sopenharmony_ci if (val & ISAR_IRQSTA) 1288c2ecf20Sopenharmony_ci mISDNisar_irq(&sf->isar); 1298c2ecf20Sopenharmony_ci val = ReadISAC_IND(sf, ISAC_ISTA); 1308c2ecf20Sopenharmony_ci if (val) 1318c2ecf20Sopenharmony_ci mISDNisac_irq(&sf->isac, val); 1328c2ecf20Sopenharmony_ci val = ReadISAR_IND(sf, ISAR_IRQBIT); 1338c2ecf20Sopenharmony_ci if ((val & ISAR_IRQSTA) && cnt--) 1348c2ecf20Sopenharmony_ci goto Start_ISAR; 1358c2ecf20Sopenharmony_ci if (cnt < irqloops) 1368c2ecf20Sopenharmony_ci pr_debug("%s: %d irqloops cpu%d\n", sf->name, 1378c2ecf20Sopenharmony_ci irqloops - cnt, smp_processor_id()); 1388c2ecf20Sopenharmony_ci if (irqloops && !cnt) 1398c2ecf20Sopenharmony_ci pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, 1408c2ecf20Sopenharmony_ci irqloops, smp_processor_id()); 1418c2ecf20Sopenharmony_ci spin_unlock(&sf->lock); 1428c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void 1468c2ecf20Sopenharmony_cienable_hwirq(struct sfax_hw *sf) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci WriteISAC_IND(sf, ISAC_MASK, 0); 1498c2ecf20Sopenharmony_ci WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); 1508c2ecf20Sopenharmony_ci outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void 1548c2ecf20Sopenharmony_cidisable_hwirq(struct sfax_hw *sf) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci WriteISAC_IND(sf, ISAC_MASK, 0xFF); 1578c2ecf20Sopenharmony_ci WriteISAR_IND(sf, ISAR_IRQBIT, 0); 1588c2ecf20Sopenharmony_ci outb(0, sf->cfg + TIGER_AUX_IRQMASK); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void 1628c2ecf20Sopenharmony_cireset_speedfax(struct sfax_hw *sf) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci pr_debug("%s: resetting card\n", sf->name); 1668c2ecf20Sopenharmony_ci outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); 1678c2ecf20Sopenharmony_ci outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); 1688c2ecf20Sopenharmony_ci mdelay(1); 1698c2ecf20Sopenharmony_ci outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); 1708c2ecf20Sopenharmony_ci sf->aux_data = SFAX_PCI_RESET_OFF; 1718c2ecf20Sopenharmony_ci outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 1728c2ecf20Sopenharmony_ci mdelay(1); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int 1768c2ecf20Sopenharmony_cisfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci int ret = 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci switch (cmd) { 1818c2ecf20Sopenharmony_ci case HW_RESET_REQ: 1828c2ecf20Sopenharmony_ci reset_speedfax(sf); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case HW_ACTIVATE_IND: 1858c2ecf20Sopenharmony_ci if (arg & 1) 1868c2ecf20Sopenharmony_ci sf->aux_data &= ~SFAX_LED1_BIT; 1878c2ecf20Sopenharmony_ci if (arg & 2) 1888c2ecf20Sopenharmony_ci sf->aux_data &= ~SFAX_LED2_BIT; 1898c2ecf20Sopenharmony_ci outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case HW_DEACT_IND: 1928c2ecf20Sopenharmony_ci if (arg & 1) 1938c2ecf20Sopenharmony_ci sf->aux_data |= SFAX_LED1_BIT; 1948c2ecf20Sopenharmony_ci if (arg & 2) 1958c2ecf20Sopenharmony_ci sf->aux_data |= SFAX_LED2_BIT; 1968c2ecf20Sopenharmony_ci outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci default: 1998c2ecf20Sopenharmony_ci pr_info("%s: %s unknown command %x %lx\n", 2008c2ecf20Sopenharmony_ci sf->name, __func__, cmd, arg); 2018c2ecf20Sopenharmony_ci ret = -EINVAL; 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int 2088c2ecf20Sopenharmony_cichannel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int ret = 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci switch (cq->op) { 2138c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 2148c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case MISDN_CTRL_LOOP: 2178c2ecf20Sopenharmony_ci /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ 2188c2ecf20Sopenharmony_ci if (cq->channel < 0 || cq->channel > 3) { 2198c2ecf20Sopenharmony_ci ret = -EINVAL; 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case MISDN_CTRL_L1_TIMER3: 2258c2ecf20Sopenharmony_ci ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1); 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci default: 2288c2ecf20Sopenharmony_ci pr_info("%s: unknown Op %x\n", sf->name, cq->op); 2298c2ecf20Sopenharmony_ci ret = -EINVAL; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int 2368c2ecf20Sopenharmony_cisfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 2398c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 2408c2ecf20Sopenharmony_ci struct sfax_hw *sf = dch->hw; 2418c2ecf20Sopenharmony_ci struct channel_req *rq; 2428c2ecf20Sopenharmony_ci int err = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); 2458c2ecf20Sopenharmony_ci switch (cmd) { 2468c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 2478c2ecf20Sopenharmony_ci rq = arg; 2488c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) 2498c2ecf20Sopenharmony_ci err = sf->isac.open(&sf->isac, rq); 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci err = sf->isar.open(&sf->isar, rq); 2528c2ecf20Sopenharmony_ci if (err) 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 2558c2ecf20Sopenharmony_ci pr_info("%s: cannot get module\n", sf->name); 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 2588c2ecf20Sopenharmony_ci pr_debug("%s: dev(%d) close from %p\n", sf->name, 2598c2ecf20Sopenharmony_ci dch->dev.id, __builtin_return_address(0)); 2608c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 2638c2ecf20Sopenharmony_ci err = channel_ctrl(sf, arg); 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci default: 2668c2ecf20Sopenharmony_ci pr_debug("%s: unknown command %x\n", sf->name, cmd); 2678c2ecf20Sopenharmony_ci return -EINVAL; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci return err; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int 2738c2ecf20Sopenharmony_ciinit_card(struct sfax_hw *sf) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int ret, cnt = 3; 2768c2ecf20Sopenharmony_ci u_long flags; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); 2798c2ecf20Sopenharmony_ci if (ret) { 2808c2ecf20Sopenharmony_ci pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci while (cnt--) { 2848c2ecf20Sopenharmony_ci spin_lock_irqsave(&sf->lock, flags); 2858c2ecf20Sopenharmony_ci ret = sf->isac.init(&sf->isac); 2868c2ecf20Sopenharmony_ci if (ret) { 2878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sf->lock, flags); 2888c2ecf20Sopenharmony_ci pr_info("%s: ISAC init failed with %d\n", 2898c2ecf20Sopenharmony_ci sf->name, ret); 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci enable_hwirq(sf); 2938c2ecf20Sopenharmony_ci /* RESET Receiver and Transmitter */ 2948c2ecf20Sopenharmony_ci WriteISAC_IND(sf, ISAC_CMDR, 0x41); 2958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sf->lock, flags); 2968c2ecf20Sopenharmony_ci msleep_interruptible(10); 2978c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 2988c2ecf20Sopenharmony_ci pr_notice("%s: IRQ %d count %d\n", sf->name, 2998c2ecf20Sopenharmony_ci sf->irq, sf->irqcnt); 3008c2ecf20Sopenharmony_ci if (!sf->irqcnt) { 3018c2ecf20Sopenharmony_ci pr_info("%s: IRQ(%d) got no requests during init %d\n", 3028c2ecf20Sopenharmony_ci sf->name, sf->irq, 3 - cnt); 3038c2ecf20Sopenharmony_ci } else 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci free_irq(sf->irq, sf); 3078c2ecf20Sopenharmony_ci return -EIO; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int 3128c2ecf20Sopenharmony_cisetup_speedfax(struct sfax_hw *sf) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci u_long flags; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!request_region(sf->cfg, 256, sf->name)) { 3178c2ecf20Sopenharmony_ci pr_info("mISDN: %s config port %x-%x already in use\n", 3188c2ecf20Sopenharmony_ci sf->name, sf->cfg, sf->cfg + 255); 3198c2ecf20Sopenharmony_ci return -EIO; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci outb(0xff, sf->cfg); 3228c2ecf20Sopenharmony_ci outb(0, sf->cfg); 3238c2ecf20Sopenharmony_ci outb(0xdd, sf->cfg + TIGER_AUX_CTRL); 3248c2ecf20Sopenharmony_ci outb(0, sf->cfg + TIGER_AUX_IRQMASK); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci sf->isac.type = IPAC_TYPE_ISAC; 3278c2ecf20Sopenharmony_ci sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; 3288c2ecf20Sopenharmony_ci sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; 3298c2ecf20Sopenharmony_ci sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; 3308c2ecf20Sopenharmony_ci sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; 3318c2ecf20Sopenharmony_ci ASSIGN_FUNC(IND, ISAC, sf->isac); 3328c2ecf20Sopenharmony_ci ASSIGN_FUNC(IND, ISAR, sf->isar); 3338c2ecf20Sopenharmony_ci spin_lock_irqsave(&sf->lock, flags); 3348c2ecf20Sopenharmony_ci reset_speedfax(sf); 3358c2ecf20Sopenharmony_ci disable_hwirq(sf); 3368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sf->lock, flags); 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void 3418c2ecf20Sopenharmony_cirelease_card(struct sfax_hw *card) { 3428c2ecf20Sopenharmony_ci u_long flags; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci spin_lock_irqsave(&card->lock, flags); 3458c2ecf20Sopenharmony_ci disable_hwirq(card); 3468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&card->lock, flags); 3478c2ecf20Sopenharmony_ci card->isac.release(&card->isac); 3488c2ecf20Sopenharmony_ci free_irq(card->irq, card); 3498c2ecf20Sopenharmony_ci card->isar.release(&card->isar); 3508c2ecf20Sopenharmony_ci mISDN_unregister_device(&card->isac.dch.dev); 3518c2ecf20Sopenharmony_ci release_region(card->cfg, 256); 3528c2ecf20Sopenharmony_ci pci_disable_device(card->pdev); 3538c2ecf20Sopenharmony_ci pci_set_drvdata(card->pdev, NULL); 3548c2ecf20Sopenharmony_ci write_lock_irqsave(&card_lock, flags); 3558c2ecf20Sopenharmony_ci list_del(&card->list); 3568c2ecf20Sopenharmony_ci write_unlock_irqrestore(&card_lock, flags); 3578c2ecf20Sopenharmony_ci kfree(card); 3588c2ecf20Sopenharmony_ci sfax_cnt--; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int 3628c2ecf20Sopenharmony_cisetup_instance(struct sfax_hw *card) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci const struct firmware *firmware; 3658c2ecf20Sopenharmony_ci int i, err; 3668c2ecf20Sopenharmony_ci u_long flags; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); 3698c2ecf20Sopenharmony_ci write_lock_irqsave(&card_lock, flags); 3708c2ecf20Sopenharmony_ci list_add_tail(&card->list, &Cards); 3718c2ecf20Sopenharmony_ci write_unlock_irqrestore(&card_lock, flags); 3728c2ecf20Sopenharmony_ci _set_debug(card); 3738c2ecf20Sopenharmony_ci spin_lock_init(&card->lock); 3748c2ecf20Sopenharmony_ci card->isac.hwlock = &card->lock; 3758c2ecf20Sopenharmony_ci card->isar.hwlock = &card->lock; 3768c2ecf20Sopenharmony_ci card->isar.ctrl = (void *)&sfax_ctrl; 3778c2ecf20Sopenharmony_ci card->isac.name = card->name; 3788c2ecf20Sopenharmony_ci card->isar.name = card->name; 3798c2ecf20Sopenharmony_ci card->isar.owner = THIS_MODULE; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); 3828c2ecf20Sopenharmony_ci if (err < 0) { 3838c2ecf20Sopenharmony_ci pr_info("%s: firmware request failed %d\n", 3848c2ecf20Sopenharmony_ci card->name, err); 3858c2ecf20Sopenharmony_ci goto error_fw; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 3888c2ecf20Sopenharmony_ci pr_notice("%s: got firmware %zu bytes\n", 3898c2ecf20Sopenharmony_ci card->name, firmware->size); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci mISDNisac_init(&card->isac, card); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci card->isac.dch.dev.D.ctrl = sfax_dctrl; 3948c2ecf20Sopenharmony_ci card->isac.dch.dev.Bprotocols = 3958c2ecf20Sopenharmony_ci mISDNisar_init(&card->isar, card); 3968c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 3978c2ecf20Sopenharmony_ci set_channelmap(i + 1, card->isac.dch.dev.channelmap); 3988c2ecf20Sopenharmony_ci list_add(&card->isar.ch[i].bch.ch.list, 3998c2ecf20Sopenharmony_ci &card->isac.dch.dev.bchannels); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci err = setup_speedfax(card); 4038c2ecf20Sopenharmony_ci if (err) 4048c2ecf20Sopenharmony_ci goto error_setup; 4058c2ecf20Sopenharmony_ci err = card->isar.init(&card->isar); 4068c2ecf20Sopenharmony_ci if (err) 4078c2ecf20Sopenharmony_ci goto error; 4088c2ecf20Sopenharmony_ci err = mISDN_register_device(&card->isac.dch.dev, 4098c2ecf20Sopenharmony_ci &card->pdev->dev, card->name); 4108c2ecf20Sopenharmony_ci if (err) 4118c2ecf20Sopenharmony_ci goto error; 4128c2ecf20Sopenharmony_ci err = init_card(card); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci goto error_init; 4158c2ecf20Sopenharmony_ci err = card->isar.firmware(&card->isar, firmware->data, firmware->size); 4168c2ecf20Sopenharmony_ci if (!err) { 4178c2ecf20Sopenharmony_ci release_firmware(firmware); 4188c2ecf20Sopenharmony_ci sfax_cnt++; 4198c2ecf20Sopenharmony_ci pr_notice("SpeedFax %d cards installed\n", sfax_cnt); 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci disable_hwirq(card); 4238c2ecf20Sopenharmony_ci free_irq(card->irq, card); 4248c2ecf20Sopenharmony_cierror_init: 4258c2ecf20Sopenharmony_ci mISDN_unregister_device(&card->isac.dch.dev); 4268c2ecf20Sopenharmony_cierror: 4278c2ecf20Sopenharmony_ci release_region(card->cfg, 256); 4288c2ecf20Sopenharmony_cierror_setup: 4298c2ecf20Sopenharmony_ci card->isac.release(&card->isac); 4308c2ecf20Sopenharmony_ci card->isar.release(&card->isar); 4318c2ecf20Sopenharmony_ci release_firmware(firmware); 4328c2ecf20Sopenharmony_cierror_fw: 4338c2ecf20Sopenharmony_ci pci_disable_device(card->pdev); 4348c2ecf20Sopenharmony_ci write_lock_irqsave(&card_lock, flags); 4358c2ecf20Sopenharmony_ci list_del(&card->list); 4368c2ecf20Sopenharmony_ci write_unlock_irqrestore(&card_lock, flags); 4378c2ecf20Sopenharmony_ci kfree(card); 4388c2ecf20Sopenharmony_ci return err; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int 4428c2ecf20Sopenharmony_cisfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int err = -ENOMEM; 4458c2ecf20Sopenharmony_ci struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!card) { 4488c2ecf20Sopenharmony_ci pr_info("No memory for Speedfax+ PCI\n"); 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci card->pdev = pdev; 4528c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 4538c2ecf20Sopenharmony_ci if (err) { 4548c2ecf20Sopenharmony_ci kfree(card); 4558c2ecf20Sopenharmony_ci return err; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci pr_notice("mISDN: Speedfax found adapter %s at %s\n", 4598c2ecf20Sopenharmony_ci (char *)ent->driver_data, pci_name(pdev)); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci card->cfg = pci_resource_start(pdev, 0); 4628c2ecf20Sopenharmony_ci card->irq = pdev->irq; 4638c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, card); 4648c2ecf20Sopenharmony_ci err = setup_instance(card); 4658c2ecf20Sopenharmony_ci if (err) 4668c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void 4718c2ecf20Sopenharmony_cisfax_remove_pci(struct pci_dev *pdev) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct sfax_hw *card = pci_get_drvdata(pdev); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (card) 4768c2ecf20Sopenharmony_ci release_card(card); 4778c2ecf20Sopenharmony_ci else 4788c2ecf20Sopenharmony_ci pr_debug("%s: drvdata already removed\n", __func__); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic struct pci_device_id sfaxpci_ids[] = { 4828c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, 4838c2ecf20Sopenharmony_ci PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, 4848c2ecf20Sopenharmony_ci 0, 0, (unsigned long) "Pyramid Speedfax + PCI" 4858c2ecf20Sopenharmony_ci }, 4868c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, 4878c2ecf20Sopenharmony_ci PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, 4888c2ecf20Sopenharmony_ci 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" 4898c2ecf20Sopenharmony_ci }, 4908c2ecf20Sopenharmony_ci { } 4918c2ecf20Sopenharmony_ci}; 4928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sfaxpci_ids); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic struct pci_driver sfaxpci_driver = { 4958c2ecf20Sopenharmony_ci .name = "speedfax+ pci", 4968c2ecf20Sopenharmony_ci .probe = sfaxpci_probe, 4978c2ecf20Sopenharmony_ci .remove = sfax_remove_pci, 4988c2ecf20Sopenharmony_ci .id_table = sfaxpci_ids, 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int __init 5028c2ecf20Sopenharmony_ciSpeedfax_init(void) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int err; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", 5078c2ecf20Sopenharmony_ci SPEEDFAX_REV); 5088c2ecf20Sopenharmony_ci err = pci_register_driver(&sfaxpci_driver); 5098c2ecf20Sopenharmony_ci return err; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void __exit 5138c2ecf20Sopenharmony_ciSpeedfax_cleanup(void) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci pci_unregister_driver(&sfaxpci_driver); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cimodule_init(Speedfax_init); 5198c2ecf20Sopenharmony_cimodule_exit(Speedfax_cleanup); 520