Path: blob/master/drivers/isdn/hardware/mISDN/speedfax.c
15112 views
/*1* speedfax.c low level stuff for Sedlbauer Speedfax+ cards2* based on the ISAR DSP3* Thanks to Sedlbauer AG for informations and HW4*5* Author Karsten Keil <[email protected]>6*7* Copyright 2009 by Karsten Keil <[email protected]>8*9* This program is free software; you can redistribute it and/or modify10* it under the terms of the GNU General Public License version 2 as11* published by the Free Software Foundation.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.21*22*/2324#include <linux/module.h>25#include <linux/slab.h>26#include <linux/pci.h>27#include <linux/delay.h>28#include <linux/mISDNhw.h>29#include <linux/firmware.h>30#include "ipac.h"31#include "isar.h"3233#define SPEEDFAX_REV "2.0"3435#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x5136#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x5437#define PCI_SUB_ID_SEDLBAUER 0x013839#define SFAX_PCI_ADDR 0xc840#define SFAX_PCI_ISAC 0xd041#define SFAX_PCI_ISAR 0xe04243/* TIGER 100 Registers */4445#define TIGER_RESET_ADDR 0x0046#define TIGER_EXTERN_RESET_ON 0x0147#define TIGER_EXTERN_RESET_OFF 0x0048#define TIGER_AUX_CTRL 0x0249#define TIGER_AUX_DATA 0x0350#define TIGER_AUX_IRQMASK 0x0551#define TIGER_AUX_STATUS 0x075253/* Tiger AUX BITs */54#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */55#define SFAX_ISAR_RESET_BIT_OFF 0x0056#define SFAX_ISAR_RESET_BIT_ON 0x0157#define SFAX_TIGER_IRQ_BIT 0x0258#define SFAX_LED1_BIT 0x0859#define SFAX_LED2_BIT 0x106061#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON)62#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT)6364static int sfax_cnt;65static u32 debug;66static u32 irqloops = 4;6768struct sfax_hw {69struct list_head list;70struct pci_dev *pdev;71char name[MISDN_MAX_IDLEN];72u32 irq;73u32 irqcnt;74u32 cfg;75struct _ioport p_isac;76struct _ioport p_isar;77u8 aux_data;78spinlock_t lock; /* HW access lock */79struct isac_hw isac;80struct isar_hw isar;81};8283static LIST_HEAD(Cards);84static DEFINE_RWLOCK(card_lock); /* protect Cards */8586static void87_set_debug(struct sfax_hw *card)88{89card->isac.dch.debug = debug;90card->isar.ch[0].bch.debug = debug;91card->isar.ch[1].bch.debug = debug;92}9394static int95set_debug(const char *val, struct kernel_param *kp)96{97int ret;98struct sfax_hw *card;99100ret = param_set_uint(val, kp);101if (!ret) {102read_lock(&card_lock);103list_for_each_entry(card, &Cards, list)104_set_debug(card);105read_unlock(&card_lock);106}107return ret;108}109110MODULE_AUTHOR("Karsten Keil");111MODULE_LICENSE("GPL v2");112MODULE_VERSION(SPEEDFAX_REV);113MODULE_FIRMWARE("isdn/ISAR.BIN");114module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);115MODULE_PARM_DESC(debug, "Speedfax debug mask");116module_param(irqloops, uint, S_IRUGO | S_IWUSR);117MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");118119IOFUNC_IND(ISAC, sfax_hw, p_isac)120IOFUNC_IND(ISAR, sfax_hw, p_isar)121122static irqreturn_t123speedfax_irq(int intno, void *dev_id)124{125struct sfax_hw *sf = dev_id;126u8 val;127int cnt = irqloops;128129spin_lock(&sf->lock);130val = inb(sf->cfg + TIGER_AUX_STATUS);131if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */132spin_unlock(&sf->lock);133return IRQ_NONE; /* shared */134}135sf->irqcnt++;136val = ReadISAR_IND(sf, ISAR_IRQBIT);137Start_ISAR:138if (val & ISAR_IRQSTA)139mISDNisar_irq(&sf->isar);140val = ReadISAC_IND(sf, ISAC_ISTA);141if (val)142mISDNisac_irq(&sf->isac, val);143val = ReadISAR_IND(sf, ISAR_IRQBIT);144if ((val & ISAR_IRQSTA) && cnt--)145goto Start_ISAR;146if (cnt < irqloops)147pr_debug("%s: %d irqloops cpu%d\n", sf->name,148irqloops - cnt, smp_processor_id());149if (irqloops && !cnt)150pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,151irqloops, smp_processor_id());152spin_unlock(&sf->lock);153return IRQ_HANDLED;154}155156static void157enable_hwirq(struct sfax_hw *sf)158{159WriteISAC_IND(sf, ISAC_MASK, 0);160WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);161outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);162}163164static void165disable_hwirq(struct sfax_hw *sf)166{167WriteISAC_IND(sf, ISAC_MASK, 0xFF);168WriteISAR_IND(sf, ISAR_IRQBIT, 0);169outb(0, sf->cfg + TIGER_AUX_IRQMASK);170}171172static void173reset_speedfax(struct sfax_hw *sf)174{175176pr_debug("%s: resetting card\n", sf->name);177outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);178outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);179mdelay(1);180outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);181sf->aux_data = SFAX_PCI_RESET_OFF;182outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);183mdelay(1);184}185186static int187sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg)188{189int ret = 0;190191switch (cmd) {192case HW_RESET_REQ:193reset_speedfax(sf);194break;195case HW_ACTIVATE_IND:196if (arg & 1)197sf->aux_data &= ~SFAX_LED1_BIT;198if (arg & 2)199sf->aux_data &= ~SFAX_LED2_BIT;200outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);201break;202case HW_DEACT_IND:203if (arg & 1)204sf->aux_data |= SFAX_LED1_BIT;205if (arg & 2)206sf->aux_data |= SFAX_LED2_BIT;207outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);208break;209default:210pr_info("%s: %s unknown command %x %lx\n",211sf->name, __func__, cmd, arg);212ret = -EINVAL;213break;214}215return ret;216}217218static int219channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq)220{221int ret = 0;222223switch (cq->op) {224case MISDN_CTRL_GETOP:225cq->op = MISDN_CTRL_LOOP;226break;227case MISDN_CTRL_LOOP:228/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */229if (cq->channel < 0 || cq->channel > 3) {230ret = -EINVAL;231break;232}233ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);234break;235default:236pr_info("%s: unknown Op %x\n", sf->name, cq->op);237ret = -EINVAL;238break;239}240return ret;241}242243static int244sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)245{246struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);247struct dchannel *dch = container_of(dev, struct dchannel, dev);248struct sfax_hw *sf = dch->hw;249struct channel_req *rq;250int err = 0;251252pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);253switch (cmd) {254case OPEN_CHANNEL:255rq = arg;256if (rq->protocol == ISDN_P_TE_S0)257err = sf->isac.open(&sf->isac, rq);258else259err = sf->isar.open(&sf->isar, rq);260if (err)261break;262if (!try_module_get(THIS_MODULE))263pr_info("%s: cannot get module\n", sf->name);264break;265case CLOSE_CHANNEL:266pr_debug("%s: dev(%d) close from %p\n", sf->name,267dch->dev.id, __builtin_return_address(0));268module_put(THIS_MODULE);269break;270case CONTROL_CHANNEL:271err = channel_ctrl(sf, arg);272break;273default:274pr_debug("%s: unknown command %x\n", sf->name, cmd);275return -EINVAL;276}277return err;278}279280static int __devinit281init_card(struct sfax_hw *sf)282{283int ret, cnt = 3;284u_long flags;285286ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);287if (ret) {288pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);289return ret;290}291while (cnt--) {292spin_lock_irqsave(&sf->lock, flags);293ret = sf->isac.init(&sf->isac);294if (ret) {295spin_unlock_irqrestore(&sf->lock, flags);296pr_info("%s: ISAC init failed with %d\n",297sf->name, ret);298break;299}300enable_hwirq(sf);301/* RESET Receiver and Transmitter */302WriteISAC_IND(sf, ISAC_CMDR, 0x41);303spin_unlock_irqrestore(&sf->lock, flags);304msleep_interruptible(10);305if (debug & DEBUG_HW)306pr_notice("%s: IRQ %d count %d\n", sf->name,307sf->irq, sf->irqcnt);308if (!sf->irqcnt) {309pr_info("%s: IRQ(%d) got no requests during init %d\n",310sf->name, sf->irq, 3 - cnt);311} else312return 0;313}314free_irq(sf->irq, sf);315return -EIO;316}317318319static int __devinit320setup_speedfax(struct sfax_hw *sf)321{322u_long flags;323324if (!request_region(sf->cfg, 256, sf->name)) {325pr_info("mISDN: %s config port %x-%x already in use\n",326sf->name, sf->cfg, sf->cfg + 255);327return -EIO;328}329outb(0xff, sf->cfg);330outb(0, sf->cfg);331outb(0xdd, sf->cfg + TIGER_AUX_CTRL);332outb(0, sf->cfg + TIGER_AUX_IRQMASK);333334sf->isac.type = IPAC_TYPE_ISAC;335sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;336sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;337sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;338sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;339ASSIGN_FUNC(IND, ISAC, sf->isac);340ASSIGN_FUNC(IND, ISAR, sf->isar);341spin_lock_irqsave(&sf->lock, flags);342reset_speedfax(sf);343disable_hwirq(sf);344spin_unlock_irqrestore(&sf->lock, flags);345return 0;346}347348static void349release_card(struct sfax_hw *card) {350u_long flags;351352spin_lock_irqsave(&card->lock, flags);353disable_hwirq(card);354spin_unlock_irqrestore(&card->lock, flags);355card->isac.release(&card->isac);356free_irq(card->irq, card);357card->isar.release(&card->isar);358mISDN_unregister_device(&card->isac.dch.dev);359release_region(card->cfg, 256);360pci_disable_device(card->pdev);361pci_set_drvdata(card->pdev, NULL);362write_lock_irqsave(&card_lock, flags);363list_del(&card->list);364write_unlock_irqrestore(&card_lock, flags);365kfree(card);366sfax_cnt--;367}368369static int __devinit370setup_instance(struct sfax_hw *card)371{372const struct firmware *firmware;373int i, err;374u_long flags;375376snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);377write_lock_irqsave(&card_lock, flags);378list_add_tail(&card->list, &Cards);379write_unlock_irqrestore(&card_lock, flags);380_set_debug(card);381spin_lock_init(&card->lock);382card->isac.hwlock = &card->lock;383card->isar.hwlock = &card->lock;384card->isar.ctrl = (void *)&sfax_ctrl;385card->isac.name = card->name;386card->isar.name = card->name;387card->isar.owner = THIS_MODULE;388389err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);390if (err < 0) {391pr_info("%s: firmware request failed %d\n",392card->name, err);393goto error_fw;394}395if (debug & DEBUG_HW)396pr_notice("%s: got firmware %zu bytes\n",397card->name, firmware->size);398399mISDNisac_init(&card->isac, card);400401card->isac.dch.dev.D.ctrl = sfax_dctrl;402card->isac.dch.dev.Bprotocols =403mISDNisar_init(&card->isar, card);404for (i = 0; i < 2; i++) {405set_channelmap(i + 1, card->isac.dch.dev.channelmap);406list_add(&card->isar.ch[i].bch.ch.list,407&card->isac.dch.dev.bchannels);408}409410err = setup_speedfax(card);411if (err)412goto error_setup;413err = card->isar.init(&card->isar);414if (err)415goto error;416err = mISDN_register_device(&card->isac.dch.dev,417&card->pdev->dev, card->name);418if (err)419goto error;420err = init_card(card);421if (err)422goto error_init;423err = card->isar.firmware(&card->isar, firmware->data, firmware->size);424if (!err) {425release_firmware(firmware);426sfax_cnt++;427pr_notice("SpeedFax %d cards installed\n", sfax_cnt);428return 0;429}430disable_hwirq(card);431free_irq(card->irq, card);432error_init:433mISDN_unregister_device(&card->isac.dch.dev);434error:435release_region(card->cfg, 256);436error_setup:437card->isac.release(&card->isac);438card->isar.release(&card->isar);439release_firmware(firmware);440error_fw:441pci_disable_device(card->pdev);442write_lock_irqsave(&card_lock, flags);443list_del(&card->list);444write_unlock_irqrestore(&card_lock, flags);445kfree(card);446return err;447}448449static int __devinit450sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)451{452int err = -ENOMEM;453struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL);454455if (!card) {456pr_info("No memory for Speedfax+ PCI\n");457return err;458}459card->pdev = pdev;460err = pci_enable_device(pdev);461if (err) {462kfree(card);463return err;464}465466pr_notice("mISDN: Speedfax found adapter %s at %s\n",467(char *)ent->driver_data, pci_name(pdev));468469card->cfg = pci_resource_start(pdev, 0);470card->irq = pdev->irq;471pci_set_drvdata(pdev, card);472err = setup_instance(card);473if (err)474pci_set_drvdata(pdev, NULL);475return err;476}477478static void __devexit479sfax_remove_pci(struct pci_dev *pdev)480{481struct sfax_hw *card = pci_get_drvdata(pdev);482483if (card)484release_card(card);485else486pr_debug("%s: drvdata already removed\n", __func__);487}488489static struct pci_device_id sfaxpci_ids[] __devinitdata = {490{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,491PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,4920, 0, (unsigned long) "Pyramid Speedfax + PCI"493},494{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,495PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,4960, 0, (unsigned long) "Sedlbauer Speedfax + PCI"497},498{ }499};500MODULE_DEVICE_TABLE(pci, sfaxpci_ids);501502static struct pci_driver sfaxpci_driver = {503.name = "speedfax+ pci",504.probe = sfaxpci_probe,505.remove = __devexit_p(sfax_remove_pci),506.id_table = sfaxpci_ids,507};508509static int __init510Speedfax_init(void)511{512int err;513514pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",515SPEEDFAX_REV);516err = pci_register_driver(&sfaxpci_driver);517return err;518}519520static void __exit521Speedfax_cleanup(void)522{523pci_unregister_driver(&sfaxpci_driver);524}525526module_init(Speedfax_init);527module_exit(Speedfax_cleanup);528529530