182c29810SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2da2272c9SKarsten Keil /* 3da2272c9SKarsten Keil * speedfax.c low level stuff for Sedlbauer Speedfax+ cards 4da2272c9SKarsten Keil * based on the ISAR DSP 5da2272c9SKarsten Keil * Thanks to Sedlbauer AG for informations and HW 6da2272c9SKarsten Keil * 7da2272c9SKarsten Keil * Author Karsten Keil <keil@isdn4linux.de> 8da2272c9SKarsten Keil * 9da2272c9SKarsten Keil * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 10da2272c9SKarsten Keil */ 11da2272c9SKarsten Keil 12a6b7a407SAlexey Dobriyan #include <linux/interrupt.h> 13da2272c9SKarsten Keil #include <linux/module.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 15da2272c9SKarsten Keil #include <linux/pci.h> 16da2272c9SKarsten Keil #include <linux/delay.h> 17da2272c9SKarsten Keil #include <linux/mISDNhw.h> 18da2272c9SKarsten Keil #include <linux/firmware.h> 19da2272c9SKarsten Keil #include "ipac.h" 20da2272c9SKarsten Keil #include "isar.h" 21da2272c9SKarsten Keil 22da2272c9SKarsten Keil #define SPEEDFAX_REV "2.0" 23da2272c9SKarsten Keil 24da2272c9SKarsten Keil #define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 25da2272c9SKarsten Keil #define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 26da2272c9SKarsten Keil #define PCI_SUB_ID_SEDLBAUER 0x01 27da2272c9SKarsten Keil 28da2272c9SKarsten Keil #define SFAX_PCI_ADDR 0xc8 29da2272c9SKarsten Keil #define SFAX_PCI_ISAC 0xd0 30da2272c9SKarsten Keil #define SFAX_PCI_ISAR 0xe0 31da2272c9SKarsten Keil 32da2272c9SKarsten Keil /* TIGER 100 Registers */ 33da2272c9SKarsten Keil 34da2272c9SKarsten Keil #define TIGER_RESET_ADDR 0x00 35da2272c9SKarsten Keil #define TIGER_EXTERN_RESET_ON 0x01 36da2272c9SKarsten Keil #define TIGER_EXTERN_RESET_OFF 0x00 37da2272c9SKarsten Keil #define TIGER_AUX_CTRL 0x02 38da2272c9SKarsten Keil #define TIGER_AUX_DATA 0x03 39da2272c9SKarsten Keil #define TIGER_AUX_IRQMASK 0x05 40da2272c9SKarsten Keil #define TIGER_AUX_STATUS 0x07 41da2272c9SKarsten Keil 42da2272c9SKarsten Keil /* Tiger AUX BITs */ 43da2272c9SKarsten Keil #define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */ 44da2272c9SKarsten Keil #define SFAX_ISAR_RESET_BIT_OFF 0x00 45da2272c9SKarsten Keil #define SFAX_ISAR_RESET_BIT_ON 0x01 46da2272c9SKarsten Keil #define SFAX_TIGER_IRQ_BIT 0x02 47da2272c9SKarsten Keil #define SFAX_LED1_BIT 0x08 48da2272c9SKarsten Keil #define SFAX_LED2_BIT 0x10 49da2272c9SKarsten Keil 50da2272c9SKarsten Keil #define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON) 51da2272c9SKarsten Keil #define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT) 52da2272c9SKarsten Keil 53da2272c9SKarsten Keil static int sfax_cnt; 54da2272c9SKarsten Keil static u32 debug; 55da2272c9SKarsten Keil static u32 irqloops = 4; 56da2272c9SKarsten Keil 57da2272c9SKarsten Keil struct sfax_hw { 58da2272c9SKarsten Keil struct list_head list; 59da2272c9SKarsten Keil struct pci_dev *pdev; 60da2272c9SKarsten Keil char name[MISDN_MAX_IDLEN]; 61da2272c9SKarsten Keil u32 irq; 62da2272c9SKarsten Keil u32 irqcnt; 63da2272c9SKarsten Keil u32 cfg; 64da2272c9SKarsten Keil struct _ioport p_isac; 65da2272c9SKarsten Keil struct _ioport p_isar; 66da2272c9SKarsten Keil u8 aux_data; 67da2272c9SKarsten Keil spinlock_t lock; /* HW access lock */ 68da2272c9SKarsten Keil struct isac_hw isac; 69da2272c9SKarsten Keil struct isar_hw isar; 70da2272c9SKarsten Keil }; 71da2272c9SKarsten Keil 72da2272c9SKarsten Keil static LIST_HEAD(Cards); 73da2272c9SKarsten Keil static DEFINE_RWLOCK(card_lock); /* protect Cards */ 74da2272c9SKarsten Keil 75da2272c9SKarsten Keil static void 76da2272c9SKarsten Keil _set_debug(struct sfax_hw *card) 77da2272c9SKarsten Keil { 78da2272c9SKarsten Keil card->isac.dch.debug = debug; 79da2272c9SKarsten Keil card->isar.ch[0].bch.debug = debug; 80da2272c9SKarsten Keil card->isar.ch[1].bch.debug = debug; 81da2272c9SKarsten Keil } 82da2272c9SKarsten Keil 83da2272c9SKarsten Keil static int 84e4dca7b7SKees Cook set_debug(const char *val, const struct kernel_param *kp) 85da2272c9SKarsten Keil { 86da2272c9SKarsten Keil int ret; 87da2272c9SKarsten Keil struct sfax_hw *card; 88da2272c9SKarsten Keil 89da2272c9SKarsten Keil ret = param_set_uint(val, kp); 90da2272c9SKarsten Keil if (!ret) { 91da2272c9SKarsten Keil read_lock(&card_lock); 92da2272c9SKarsten Keil list_for_each_entry(card, &Cards, list) 93da2272c9SKarsten Keil _set_debug(card); 94da2272c9SKarsten Keil read_unlock(&card_lock); 95da2272c9SKarsten Keil } 96da2272c9SKarsten Keil return ret; 97da2272c9SKarsten Keil } 98da2272c9SKarsten Keil 99da2272c9SKarsten Keil MODULE_AUTHOR("Karsten Keil"); 100*2ebb87f4SJeff Johnson MODULE_DESCRIPTION("mISDN driver for Sedlbauer Speedfax+ cards"); 101da2272c9SKarsten Keil MODULE_LICENSE("GPL v2"); 102da2272c9SKarsten Keil MODULE_VERSION(SPEEDFAX_REV); 1034a9b5e50SBen Hutchings MODULE_FIRMWARE("isdn/ISAR.BIN"); 104da2272c9SKarsten Keil module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); 105da2272c9SKarsten Keil MODULE_PARM_DESC(debug, "Speedfax debug mask"); 106da2272c9SKarsten Keil module_param(irqloops, uint, S_IRUGO | S_IWUSR); 107da2272c9SKarsten Keil MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)"); 108da2272c9SKarsten Keil 109da2272c9SKarsten Keil IOFUNC_IND(ISAC, sfax_hw, p_isac) 110da2272c9SKarsten Keil IOFUNC_IND(ISAR, sfax_hw, p_isar) 111da2272c9SKarsten Keil 112da2272c9SKarsten Keil static irqreturn_t 113da2272c9SKarsten Keil speedfax_irq(int intno, void *dev_id) 114da2272c9SKarsten Keil { 115da2272c9SKarsten Keil struct sfax_hw *sf = dev_id; 116da2272c9SKarsten Keil u8 val; 117da2272c9SKarsten Keil int cnt = irqloops; 118da2272c9SKarsten Keil 119da2272c9SKarsten Keil spin_lock(&sf->lock); 120da2272c9SKarsten Keil val = inb(sf->cfg + TIGER_AUX_STATUS); 121da2272c9SKarsten Keil if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */ 122da2272c9SKarsten Keil spin_unlock(&sf->lock); 123da2272c9SKarsten Keil return IRQ_NONE; /* shared */ 124da2272c9SKarsten Keil } 125da2272c9SKarsten Keil sf->irqcnt++; 126da2272c9SKarsten Keil val = ReadISAR_IND(sf, ISAR_IRQBIT); 127da2272c9SKarsten Keil Start_ISAR: 128da2272c9SKarsten Keil if (val & ISAR_IRQSTA) 129da2272c9SKarsten Keil mISDNisar_irq(&sf->isar); 130da2272c9SKarsten Keil val = ReadISAC_IND(sf, ISAC_ISTA); 131da2272c9SKarsten Keil if (val) 132da2272c9SKarsten Keil mISDNisac_irq(&sf->isac, val); 133da2272c9SKarsten Keil val = ReadISAR_IND(sf, ISAR_IRQBIT); 134da2272c9SKarsten Keil if ((val & ISAR_IRQSTA) && cnt--) 135da2272c9SKarsten Keil goto Start_ISAR; 136da2272c9SKarsten Keil if (cnt < irqloops) 137da2272c9SKarsten Keil pr_debug("%s: %d irqloops cpu%d\n", sf->name, 138da2272c9SKarsten Keil irqloops - cnt, smp_processor_id()); 139da2272c9SKarsten Keil if (irqloops && !cnt) 140da2272c9SKarsten Keil pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name, 141da2272c9SKarsten Keil irqloops, smp_processor_id()); 142da2272c9SKarsten Keil spin_unlock(&sf->lock); 143da2272c9SKarsten Keil return IRQ_HANDLED; 144da2272c9SKarsten Keil } 145da2272c9SKarsten Keil 146da2272c9SKarsten Keil static void 147da2272c9SKarsten Keil enable_hwirq(struct sfax_hw *sf) 148da2272c9SKarsten Keil { 149da2272c9SKarsten Keil WriteISAC_IND(sf, ISAC_MASK, 0); 150da2272c9SKarsten Keil WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK); 151da2272c9SKarsten Keil outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK); 152da2272c9SKarsten Keil } 153da2272c9SKarsten Keil 154da2272c9SKarsten Keil static void 155da2272c9SKarsten Keil disable_hwirq(struct sfax_hw *sf) 156da2272c9SKarsten Keil { 157da2272c9SKarsten Keil WriteISAC_IND(sf, ISAC_MASK, 0xFF); 158da2272c9SKarsten Keil WriteISAR_IND(sf, ISAR_IRQBIT, 0); 159da2272c9SKarsten Keil outb(0, sf->cfg + TIGER_AUX_IRQMASK); 160da2272c9SKarsten Keil } 161da2272c9SKarsten Keil 162da2272c9SKarsten Keil static void 163da2272c9SKarsten Keil reset_speedfax(struct sfax_hw *sf) 164da2272c9SKarsten Keil { 165da2272c9SKarsten Keil 166da2272c9SKarsten Keil pr_debug("%s: resetting card\n", sf->name); 167da2272c9SKarsten Keil outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR); 168da2272c9SKarsten Keil outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA); 169da2272c9SKarsten Keil mdelay(1); 170da2272c9SKarsten Keil outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR); 171da2272c9SKarsten Keil sf->aux_data = SFAX_PCI_RESET_OFF; 172da2272c9SKarsten Keil outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 173da2272c9SKarsten Keil mdelay(1); 174da2272c9SKarsten Keil } 175da2272c9SKarsten Keil 176da2272c9SKarsten Keil static int 177da2272c9SKarsten Keil sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg) 178da2272c9SKarsten Keil { 179da2272c9SKarsten Keil int ret = 0; 180da2272c9SKarsten Keil 181da2272c9SKarsten Keil switch (cmd) { 182da2272c9SKarsten Keil case HW_RESET_REQ: 183da2272c9SKarsten Keil reset_speedfax(sf); 184da2272c9SKarsten Keil break; 185da2272c9SKarsten Keil case HW_ACTIVATE_IND: 186da2272c9SKarsten Keil if (arg & 1) 187da2272c9SKarsten Keil sf->aux_data &= ~SFAX_LED1_BIT; 188da2272c9SKarsten Keil if (arg & 2) 189da2272c9SKarsten Keil sf->aux_data &= ~SFAX_LED2_BIT; 190da2272c9SKarsten Keil outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 191da2272c9SKarsten Keil break; 192da2272c9SKarsten Keil case HW_DEACT_IND: 193da2272c9SKarsten Keil if (arg & 1) 194da2272c9SKarsten Keil sf->aux_data |= SFAX_LED1_BIT; 195da2272c9SKarsten Keil if (arg & 2) 196da2272c9SKarsten Keil sf->aux_data |= SFAX_LED2_BIT; 197da2272c9SKarsten Keil outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA); 198da2272c9SKarsten Keil break; 199da2272c9SKarsten Keil default: 200da2272c9SKarsten Keil pr_info("%s: %s unknown command %x %lx\n", 201da2272c9SKarsten Keil sf->name, __func__, cmd, arg); 202da2272c9SKarsten Keil ret = -EINVAL; 203da2272c9SKarsten Keil break; 204da2272c9SKarsten Keil } 205da2272c9SKarsten Keil return ret; 206da2272c9SKarsten Keil } 207da2272c9SKarsten Keil 208da2272c9SKarsten Keil static int 209da2272c9SKarsten Keil channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq) 210da2272c9SKarsten Keil { 211da2272c9SKarsten Keil int ret = 0; 212da2272c9SKarsten Keil 213da2272c9SKarsten Keil switch (cq->op) { 214da2272c9SKarsten Keil case MISDN_CTRL_GETOP: 215c626c127SKarsten Keil cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; 216da2272c9SKarsten Keil break; 217da2272c9SKarsten Keil case MISDN_CTRL_LOOP: 218da2272c9SKarsten Keil /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ 219da2272c9SKarsten Keil if (cq->channel < 0 || cq->channel > 3) { 220da2272c9SKarsten Keil ret = -EINVAL; 221da2272c9SKarsten Keil break; 222da2272c9SKarsten Keil } 223da2272c9SKarsten Keil ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel); 224da2272c9SKarsten Keil break; 225c626c127SKarsten Keil case MISDN_CTRL_L1_TIMER3: 226c626c127SKarsten Keil ret = sf->isac.ctrl(&sf->isac, HW_TIMER3_VALUE, cq->p1); 227c626c127SKarsten Keil break; 228da2272c9SKarsten Keil default: 229da2272c9SKarsten Keil pr_info("%s: unknown Op %x\n", sf->name, cq->op); 230da2272c9SKarsten Keil ret = -EINVAL; 231da2272c9SKarsten Keil break; 232da2272c9SKarsten Keil } 233da2272c9SKarsten Keil return ret; 234da2272c9SKarsten Keil } 235da2272c9SKarsten Keil 236da2272c9SKarsten Keil static int 237da2272c9SKarsten Keil sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 238da2272c9SKarsten Keil { 239da2272c9SKarsten Keil struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 240da2272c9SKarsten Keil struct dchannel *dch = container_of(dev, struct dchannel, dev); 241da2272c9SKarsten Keil struct sfax_hw *sf = dch->hw; 242da2272c9SKarsten Keil struct channel_req *rq; 243da2272c9SKarsten Keil int err = 0; 244da2272c9SKarsten Keil 245da2272c9SKarsten Keil pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg); 246da2272c9SKarsten Keil switch (cmd) { 247da2272c9SKarsten Keil case OPEN_CHANNEL: 248da2272c9SKarsten Keil rq = arg; 249da2272c9SKarsten Keil if (rq->protocol == ISDN_P_TE_S0) 250da2272c9SKarsten Keil err = sf->isac.open(&sf->isac, rq); 251da2272c9SKarsten Keil else 252da2272c9SKarsten Keil err = sf->isar.open(&sf->isar, rq); 253da2272c9SKarsten Keil if (err) 254da2272c9SKarsten Keil break; 255da2272c9SKarsten Keil if (!try_module_get(THIS_MODULE)) 256da2272c9SKarsten Keil pr_info("%s: cannot get module\n", sf->name); 257da2272c9SKarsten Keil break; 258da2272c9SKarsten Keil case CLOSE_CHANNEL: 259da2272c9SKarsten Keil pr_debug("%s: dev(%d) close from %p\n", sf->name, 260da2272c9SKarsten Keil dch->dev.id, __builtin_return_address(0)); 261da2272c9SKarsten Keil module_put(THIS_MODULE); 262da2272c9SKarsten Keil break; 263da2272c9SKarsten Keil case CONTROL_CHANNEL: 264da2272c9SKarsten Keil err = channel_ctrl(sf, arg); 265da2272c9SKarsten Keil break; 266da2272c9SKarsten Keil default: 267da2272c9SKarsten Keil pr_debug("%s: unknown command %x\n", sf->name, cmd); 268da2272c9SKarsten Keil return -EINVAL; 269da2272c9SKarsten Keil } 270da2272c9SKarsten Keil return err; 271da2272c9SKarsten Keil } 272da2272c9SKarsten Keil 273ed5a84cdSGreg Kroah-Hartman static int 274da2272c9SKarsten Keil init_card(struct sfax_hw *sf) 275da2272c9SKarsten Keil { 276da2272c9SKarsten Keil int ret, cnt = 3; 277da2272c9SKarsten Keil u_long flags; 278da2272c9SKarsten Keil 279da2272c9SKarsten Keil ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf); 280da2272c9SKarsten Keil if (ret) { 281da2272c9SKarsten Keil pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq); 282da2272c9SKarsten Keil return ret; 283da2272c9SKarsten Keil } 284da2272c9SKarsten Keil while (cnt--) { 285da2272c9SKarsten Keil spin_lock_irqsave(&sf->lock, flags); 286da2272c9SKarsten Keil ret = sf->isac.init(&sf->isac); 287da2272c9SKarsten Keil if (ret) { 288da2272c9SKarsten Keil spin_unlock_irqrestore(&sf->lock, flags); 289da2272c9SKarsten Keil pr_info("%s: ISAC init failed with %d\n", 290da2272c9SKarsten Keil sf->name, ret); 291da2272c9SKarsten Keil break; 292da2272c9SKarsten Keil } 293da2272c9SKarsten Keil enable_hwirq(sf); 294da2272c9SKarsten Keil /* RESET Receiver and Transmitter */ 295da2272c9SKarsten Keil WriteISAC_IND(sf, ISAC_CMDR, 0x41); 296da2272c9SKarsten Keil spin_unlock_irqrestore(&sf->lock, flags); 297da2272c9SKarsten Keil msleep_interruptible(10); 298da2272c9SKarsten Keil if (debug & DEBUG_HW) 299da2272c9SKarsten Keil pr_notice("%s: IRQ %d count %d\n", sf->name, 300da2272c9SKarsten Keil sf->irq, sf->irqcnt); 301da2272c9SKarsten Keil if (!sf->irqcnt) { 302da2272c9SKarsten Keil pr_info("%s: IRQ(%d) got no requests during init %d\n", 303da2272c9SKarsten Keil sf->name, sf->irq, 3 - cnt); 304da2272c9SKarsten Keil } else 305da2272c9SKarsten Keil return 0; 306da2272c9SKarsten Keil } 307da2272c9SKarsten Keil free_irq(sf->irq, sf); 308da2272c9SKarsten Keil return -EIO; 309da2272c9SKarsten Keil } 310da2272c9SKarsten Keil 311da2272c9SKarsten Keil 312ed5a84cdSGreg Kroah-Hartman static int 313da2272c9SKarsten Keil setup_speedfax(struct sfax_hw *sf) 314da2272c9SKarsten Keil { 315da2272c9SKarsten Keil u_long flags; 316da2272c9SKarsten Keil 317da2272c9SKarsten Keil if (!request_region(sf->cfg, 256, sf->name)) { 318da2272c9SKarsten Keil pr_info("mISDN: %s config port %x-%x already in use\n", 319da2272c9SKarsten Keil sf->name, sf->cfg, sf->cfg + 255); 320da2272c9SKarsten Keil return -EIO; 321da2272c9SKarsten Keil } 322da2272c9SKarsten Keil outb(0xff, sf->cfg); 323da2272c9SKarsten Keil outb(0, sf->cfg); 324da2272c9SKarsten Keil outb(0xdd, sf->cfg + TIGER_AUX_CTRL); 325da2272c9SKarsten Keil outb(0, sf->cfg + TIGER_AUX_IRQMASK); 326da2272c9SKarsten Keil 327da2272c9SKarsten Keil sf->isac.type = IPAC_TYPE_ISAC; 328da2272c9SKarsten Keil sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR; 329da2272c9SKarsten Keil sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC; 330da2272c9SKarsten Keil sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR; 331da2272c9SKarsten Keil sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR; 332da2272c9SKarsten Keil ASSIGN_FUNC(IND, ISAC, sf->isac); 333da2272c9SKarsten Keil ASSIGN_FUNC(IND, ISAR, sf->isar); 334da2272c9SKarsten Keil spin_lock_irqsave(&sf->lock, flags); 335da2272c9SKarsten Keil reset_speedfax(sf); 336da2272c9SKarsten Keil disable_hwirq(sf); 337da2272c9SKarsten Keil spin_unlock_irqrestore(&sf->lock, flags); 338da2272c9SKarsten Keil return 0; 339da2272c9SKarsten Keil } 340da2272c9SKarsten Keil 341da2272c9SKarsten Keil static void 342da2272c9SKarsten Keil release_card(struct sfax_hw *card) { 343da2272c9SKarsten Keil u_long flags; 344da2272c9SKarsten Keil 345da2272c9SKarsten Keil spin_lock_irqsave(&card->lock, flags); 346da2272c9SKarsten Keil disable_hwirq(card); 347da2272c9SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 348da2272c9SKarsten Keil card->isac.release(&card->isac); 349da2272c9SKarsten Keil free_irq(card->irq, card); 350da2272c9SKarsten Keil card->isar.release(&card->isar); 351da2272c9SKarsten Keil mISDN_unregister_device(&card->isac.dch.dev); 352da2272c9SKarsten Keil release_region(card->cfg, 256); 353da2272c9SKarsten Keil pci_disable_device(card->pdev); 354da2272c9SKarsten Keil pci_set_drvdata(card->pdev, NULL); 355da2272c9SKarsten Keil write_lock_irqsave(&card_lock, flags); 356da2272c9SKarsten Keil list_del(&card->list); 357da2272c9SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 358da2272c9SKarsten Keil kfree(card); 359da2272c9SKarsten Keil sfax_cnt--; 360da2272c9SKarsten Keil } 361da2272c9SKarsten Keil 362ed5a84cdSGreg Kroah-Hartman static int 363da2272c9SKarsten Keil setup_instance(struct sfax_hw *card) 364da2272c9SKarsten Keil { 365da2272c9SKarsten Keil const struct firmware *firmware; 366da2272c9SKarsten Keil int i, err; 367da2272c9SKarsten Keil u_long flags; 368da2272c9SKarsten Keil 369da2272c9SKarsten Keil snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1); 370da2272c9SKarsten Keil write_lock_irqsave(&card_lock, flags); 371da2272c9SKarsten Keil list_add_tail(&card->list, &Cards); 372da2272c9SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 373da2272c9SKarsten Keil _set_debug(card); 374da2272c9SKarsten Keil spin_lock_init(&card->lock); 375da2272c9SKarsten Keil card->isac.hwlock = &card->lock; 376da2272c9SKarsten Keil card->isar.hwlock = &card->lock; 377da2272c9SKarsten Keil card->isar.ctrl = (void *)&sfax_ctrl; 378da2272c9SKarsten Keil card->isac.name = card->name; 379da2272c9SKarsten Keil card->isar.name = card->name; 380da2272c9SKarsten Keil card->isar.owner = THIS_MODULE; 381da2272c9SKarsten Keil 382da2272c9SKarsten Keil err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev); 383da2272c9SKarsten Keil if (err < 0) { 384da2272c9SKarsten Keil pr_info("%s: firmware request failed %d\n", 385da2272c9SKarsten Keil card->name, err); 386da2272c9SKarsten Keil goto error_fw; 387da2272c9SKarsten Keil } 388da2272c9SKarsten Keil if (debug & DEBUG_HW) 389da2272c9SKarsten Keil pr_notice("%s: got firmware %zu bytes\n", 390da2272c9SKarsten Keil card->name, firmware->size); 391da2272c9SKarsten Keil 392da2272c9SKarsten Keil mISDNisac_init(&card->isac, card); 393da2272c9SKarsten Keil 394da2272c9SKarsten Keil card->isac.dch.dev.D.ctrl = sfax_dctrl; 395da2272c9SKarsten Keil card->isac.dch.dev.Bprotocols = 396da2272c9SKarsten Keil mISDNisar_init(&card->isar, card); 397da2272c9SKarsten Keil for (i = 0; i < 2; i++) { 398da2272c9SKarsten Keil set_channelmap(i + 1, card->isac.dch.dev.channelmap); 399da2272c9SKarsten Keil list_add(&card->isar.ch[i].bch.ch.list, 400da2272c9SKarsten Keil &card->isac.dch.dev.bchannels); 401da2272c9SKarsten Keil } 402da2272c9SKarsten Keil 403da2272c9SKarsten Keil err = setup_speedfax(card); 404da2272c9SKarsten Keil if (err) 405da2272c9SKarsten Keil goto error_setup; 406da2272c9SKarsten Keil err = card->isar.init(&card->isar); 407da2272c9SKarsten Keil if (err) 408da2272c9SKarsten Keil goto error; 409da2272c9SKarsten Keil err = mISDN_register_device(&card->isac.dch.dev, 410da2272c9SKarsten Keil &card->pdev->dev, card->name); 411da2272c9SKarsten Keil if (err) 412da2272c9SKarsten Keil goto error; 413da2272c9SKarsten Keil err = init_card(card); 414da2272c9SKarsten Keil if (err) 415da2272c9SKarsten Keil goto error_init; 416da2272c9SKarsten Keil err = card->isar.firmware(&card->isar, firmware->data, firmware->size); 417da2272c9SKarsten Keil if (!err) { 418da2272c9SKarsten Keil release_firmware(firmware); 419da2272c9SKarsten Keil sfax_cnt++; 420da2272c9SKarsten Keil pr_notice("SpeedFax %d cards installed\n", sfax_cnt); 421da2272c9SKarsten Keil return 0; 422da2272c9SKarsten Keil } 423da2272c9SKarsten Keil disable_hwirq(card); 424da2272c9SKarsten Keil free_irq(card->irq, card); 425da2272c9SKarsten Keil error_init: 426da2272c9SKarsten Keil mISDN_unregister_device(&card->isac.dch.dev); 427da2272c9SKarsten Keil error: 428da2272c9SKarsten Keil release_region(card->cfg, 256); 429da2272c9SKarsten Keil error_setup: 430da2272c9SKarsten Keil card->isac.release(&card->isac); 431da2272c9SKarsten Keil card->isar.release(&card->isar); 432da2272c9SKarsten Keil release_firmware(firmware); 433da2272c9SKarsten Keil error_fw: 434da2272c9SKarsten Keil pci_disable_device(card->pdev); 435da2272c9SKarsten Keil write_lock_irqsave(&card_lock, flags); 436da2272c9SKarsten Keil list_del(&card->list); 437da2272c9SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 438da2272c9SKarsten Keil kfree(card); 439da2272c9SKarsten Keil return err; 440da2272c9SKarsten Keil } 441da2272c9SKarsten Keil 442ed5a84cdSGreg Kroah-Hartman static int 443da2272c9SKarsten Keil sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 444da2272c9SKarsten Keil { 445da2272c9SKarsten Keil int err = -ENOMEM; 446da2272c9SKarsten Keil struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL); 447da2272c9SKarsten Keil 448da2272c9SKarsten Keil if (!card) { 449da2272c9SKarsten Keil pr_info("No memory for Speedfax+ PCI\n"); 450da2272c9SKarsten Keil return err; 451da2272c9SKarsten Keil } 452da2272c9SKarsten Keil card->pdev = pdev; 453da2272c9SKarsten Keil err = pci_enable_device(pdev); 454da2272c9SKarsten Keil if (err) { 455da2272c9SKarsten Keil kfree(card); 456da2272c9SKarsten Keil return err; 457da2272c9SKarsten Keil } 458da2272c9SKarsten Keil 459da2272c9SKarsten Keil pr_notice("mISDN: Speedfax found adapter %s at %s\n", 460da2272c9SKarsten Keil (char *)ent->driver_data, pci_name(pdev)); 461da2272c9SKarsten Keil 462da2272c9SKarsten Keil card->cfg = pci_resource_start(pdev, 0); 463da2272c9SKarsten Keil card->irq = pdev->irq; 464da2272c9SKarsten Keil pci_set_drvdata(pdev, card); 465da2272c9SKarsten Keil err = setup_instance(card); 466da2272c9SKarsten Keil if (err) 467da2272c9SKarsten Keil pci_set_drvdata(pdev, NULL); 468da2272c9SKarsten Keil return err; 469da2272c9SKarsten Keil } 470da2272c9SKarsten Keil 471ed5a84cdSGreg Kroah-Hartman static void 472da2272c9SKarsten Keil sfax_remove_pci(struct pci_dev *pdev) 473da2272c9SKarsten Keil { 474da2272c9SKarsten Keil struct sfax_hw *card = pci_get_drvdata(pdev); 475da2272c9SKarsten Keil 476da2272c9SKarsten Keil if (card) 477da2272c9SKarsten Keil release_card(card); 478da2272c9SKarsten Keil else 479698f9315SUwe Kleine-König pr_debug("%s: drvdata already removed\n", __func__); 480da2272c9SKarsten Keil } 481da2272c9SKarsten Keil 482ed5a84cdSGreg Kroah-Hartman static struct pci_device_id sfaxpci_ids[] = { 483da2272c9SKarsten Keil { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, 484da2272c9SKarsten Keil PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER, 485da2272c9SKarsten Keil 0, 0, (unsigned long) "Pyramid Speedfax + PCI" 486da2272c9SKarsten Keil }, 487da2272c9SKarsten Keil { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, 488da2272c9SKarsten Keil PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER, 489da2272c9SKarsten Keil 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI" 490da2272c9SKarsten Keil }, 491da2272c9SKarsten Keil { } 492da2272c9SKarsten Keil }; 493da2272c9SKarsten Keil MODULE_DEVICE_TABLE(pci, sfaxpci_ids); 494da2272c9SKarsten Keil 495da2272c9SKarsten Keil static struct pci_driver sfaxpci_driver = { 496da2272c9SKarsten Keil .name = "speedfax+ pci", 497da2272c9SKarsten Keil .probe = sfaxpci_probe, 498ed5a84cdSGreg Kroah-Hartman .remove = sfax_remove_pci, 499da2272c9SKarsten Keil .id_table = sfaxpci_ids, 500da2272c9SKarsten Keil }; 501da2272c9SKarsten Keil 502da2272c9SKarsten Keil static int __init 503da2272c9SKarsten Keil Speedfax_init(void) 504da2272c9SKarsten Keil { 505da2272c9SKarsten Keil int err; 506da2272c9SKarsten Keil 507da2272c9SKarsten Keil pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n", 508da2272c9SKarsten Keil SPEEDFAX_REV); 509da2272c9SKarsten Keil err = pci_register_driver(&sfaxpci_driver); 510da2272c9SKarsten Keil return err; 511da2272c9SKarsten Keil } 512da2272c9SKarsten Keil 513da2272c9SKarsten Keil static void __exit 514da2272c9SKarsten Keil Speedfax_cleanup(void) 515da2272c9SKarsten Keil { 516da2272c9SKarsten Keil pci_unregister_driver(&sfaxpci_driver); 517da2272c9SKarsten Keil } 518da2272c9SKarsten Keil 519da2272c9SKarsten Keil module_init(Speedfax_init); 520da2272c9SKarsten Keil module_exit(Speedfax_cleanup); 521