Path: blob/master/drivers/isdn/hardware/mISDN/netjet.c
15111 views
/*1* NETJet mISDN driver2*3* Author Karsten Keil <[email protected]>4*5* Copyright 2009 by Karsten Keil <[email protected]>6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License version 2 as9* published by the Free Software Foundation.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.19*20*/2122#include <linux/module.h>23#include <linux/pci.h>24#include <linux/delay.h>25#include <linux/mISDNhw.h>26#include <linux/slab.h>27#include "ipac.h"28#include "iohelper.h"29#include "netjet.h"30#include <linux/isdn/hdlc.h>3132#define NETJET_REV "2.0"3334enum nj_types {35NETJET_S_TJ300,36NETJET_S_TJ320,37ENTERNOW__TJ320,38};3940struct tiger_dma {41size_t size;42u32 *start;43int idx;44u32 dmastart;45u32 dmairq;46u32 dmaend;47u32 dmacur;48};4950struct tiger_hw;5152struct tiger_ch {53struct bchannel bch;54struct tiger_hw *nj;55int idx;56int free;57int lastrx;58u16 rxstate;59u16 txstate;60struct isdnhdlc_vars hsend;61struct isdnhdlc_vars hrecv;62u8 *hsbuf;63u8 *hrbuf;64};6566#define TX_INIT 0x000167#define TX_IDLE 0x000268#define TX_RUN 0x000469#define TX_UNDERRUN 0x010070#define RX_OVERRUN 0x01007172#define LOG_SIZE 647374struct tiger_hw {75struct list_head list;76struct pci_dev *pdev;77char name[MISDN_MAX_IDLEN];78enum nj_types typ;79int irq;80u32 irqcnt;81u32 base;82size_t base_s;83dma_addr_t dma;84void *dma_p;85spinlock_t lock; /* lock HW */86struct isac_hw isac;87struct tiger_dma send;88struct tiger_dma recv;89struct tiger_ch bc[2];90u8 ctrlreg;91u8 dmactrl;92u8 auxd;93u8 last_is0;94u8 irqmask0;95char log[LOG_SIZE];96};9798static LIST_HEAD(Cards);99static DEFINE_RWLOCK(card_lock); /* protect Cards */100static u32 debug;101static int nj_cnt;102103static void104_set_debug(struct tiger_hw *card)105{106card->isac.dch.debug = debug;107card->bc[0].bch.debug = debug;108card->bc[1].bch.debug = debug;109}110111static int112set_debug(const char *val, struct kernel_param *kp)113{114int ret;115struct tiger_hw *card;116117ret = param_set_uint(val, kp);118if (!ret) {119read_lock(&card_lock);120list_for_each_entry(card, &Cards, list)121_set_debug(card);122read_unlock(&card_lock);123}124return ret;125}126127MODULE_AUTHOR("Karsten Keil");128MODULE_LICENSE("GPL v2");129MODULE_VERSION(NETJET_REV);130module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);131MODULE_PARM_DESC(debug, "Netjet debug mask");132133static void134nj_disable_hwirq(struct tiger_hw *card)135{136outb(0, card->base + NJ_IRQMASK0);137outb(0, card->base + NJ_IRQMASK1);138}139140141static u8142ReadISAC_nj(void *p, u8 offset)143{144struct tiger_hw *card = p;145u8 ret;146147card->auxd &= 0xfc;148card->auxd |= (offset >> 4) & 3;149outb(card->auxd, card->base + NJ_AUXDATA);150ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));151return ret;152}153154static void155WriteISAC_nj(void *p, u8 offset, u8 value)156{157struct tiger_hw *card = p;158159card->auxd &= 0xfc;160card->auxd |= (offset >> 4) & 3;161outb(card->auxd, card->base + NJ_AUXDATA);162outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));163}164165static void166ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)167{168struct tiger_hw *card = p;169170card->auxd &= 0xfc;171outb(card->auxd, card->base + NJ_AUXDATA);172insb(card->base + NJ_ISAC_OFF, data, size);173}174175static void176WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)177{178struct tiger_hw *card = p;179180card->auxd &= 0xfc;181outb(card->auxd, card->base + NJ_AUXDATA);182outsb(card->base + NJ_ISAC_OFF, data, size);183}184185static void186fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)187{188struct tiger_hw *card = bc->bch.hw;189u32 mask = 0xff, val;190191pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,192bc->bch.nr, fill, cnt, idx, card->send.idx);193if (bc->bch.nr & 2) {194fill <<= 8;195mask <<= 8;196}197mask ^= 0xffffffff;198while (cnt--) {199val = card->send.start[idx];200val &= mask;201val |= fill;202card->send.start[idx++] = val;203if (idx >= card->send.size)204idx = 0;205}206}207208static int209mode_tiger(struct tiger_ch *bc, u32 protocol)210{211struct tiger_hw *card = bc->bch.hw;212213pr_debug("%s: B%1d protocol %x-->%x\n", card->name,214bc->bch.nr, bc->bch.state, protocol);215switch (protocol) {216case ISDN_P_NONE:217if (bc->bch.state == ISDN_P_NONE)218break;219fill_mem(bc, 0, card->send.size, 0xff);220bc->bch.state = protocol;221/* only stop dma and interrupts if both channels NULL */222if ((card->bc[0].bch.state == ISDN_P_NONE) &&223(card->bc[1].bch.state == ISDN_P_NONE)) {224card->dmactrl = 0;225outb(card->dmactrl, card->base + NJ_DMACTRL);226outb(0, card->base + NJ_IRQMASK0);227}228test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);229test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);230bc->txstate = 0;231bc->rxstate = 0;232bc->lastrx = -1;233break;234case ISDN_P_B_RAW:235test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);236bc->bch.state = protocol;237bc->idx = 0;238bc->free = card->send.size/2;239bc->rxstate = 0;240bc->txstate = TX_INIT | TX_IDLE;241bc->lastrx = -1;242if (!card->dmactrl) {243card->dmactrl = 1;244outb(card->dmactrl, card->base + NJ_DMACTRL);245outb(0x0f, card->base + NJ_IRQMASK0);246}247break;248case ISDN_P_B_HDLC:249test_and_set_bit(FLG_HDLC, &bc->bch.Flags);250bc->bch.state = protocol;251bc->idx = 0;252bc->free = card->send.size/2;253bc->rxstate = 0;254bc->txstate = TX_INIT | TX_IDLE;255isdnhdlc_rcv_init(&bc->hrecv, 0);256isdnhdlc_out_init(&bc->hsend, 0);257bc->lastrx = -1;258if (!card->dmactrl) {259card->dmactrl = 1;260outb(card->dmactrl, card->base + NJ_DMACTRL);261outb(0x0f, card->base + NJ_IRQMASK0);262}263break;264default:265pr_info("%s: %s protocol %x not handled\n", card->name,266__func__, protocol);267return -ENOPROTOOPT;268}269card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);270card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);271card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;272card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;273pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n",274card->name, __func__,275inb(card->base + NJ_DMACTRL),276inb(card->base + NJ_IRQMASK0),277inb(card->base + NJ_IRQSTAT0),278card->send.idx,279card->recv.idx);280return 0;281}282283static void284nj_reset(struct tiger_hw *card)285{286outb(0xff, card->base + NJ_CTRL); /* Reset On */287mdelay(1);288289/* now edge triggered for TJ320 GE 13/07/00 */290/* see comment in IRQ function */291if (card->typ == NETJET_S_TJ320) /* TJ320 */292card->ctrlreg = 0x40; /* Reset Off and status read clear */293else294card->ctrlreg = 0x00; /* Reset Off and status read clear */295outb(card->ctrlreg, card->base + NJ_CTRL);296mdelay(10);297298/* configure AUX pins (all output except ISAC IRQ pin) */299card->auxd = 0;300card->dmactrl = 0;301outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);302outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1);303outb(card->auxd, card->base + NJ_AUXDATA);304}305306static int307inittiger(struct tiger_hw *card)308{309int i;310311card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE,312&card->dma);313if (!card->dma_p) {314pr_info("%s: No DMA memory\n", card->name);315return -ENOMEM;316}317if ((u64)card->dma > 0xffffffff) {318pr_info("%s: DMA outside 32 bit\n", card->name);319return -ENOMEM;320}321for (i = 0; i < 2; i++) {322card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC);323if (!card->bc[i].hsbuf) {324pr_info("%s: no B%d send buffer\n", card->name, i + 1);325return -ENOMEM;326}327card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC);328if (!card->bc[i].hrbuf) {329pr_info("%s: no B%d recv buffer\n", card->name, i + 1);330return -ENOMEM;331}332}333memset(card->dma_p, 0xff, NJ_DMA_SIZE);334335card->send.start = card->dma_p;336card->send.dmastart = (u32)card->dma;337card->send.dmaend = card->send.dmastart +338(4 * (NJ_DMA_TXSIZE - 1));339card->send.dmairq = card->send.dmastart +340(4 * ((NJ_DMA_TXSIZE / 2) - 1));341card->send.size = NJ_DMA_TXSIZE;342343if (debug & DEBUG_HW)344pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p"345" size %zu u32\n", card->name,346card->send.dmastart, card->send.dmairq,347card->send.dmaend, card->send.start, card->send.size);348349outl(card->send.dmastart, card->base + NJ_DMA_READ_START);350outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);351outl(card->send.dmaend, card->base + NJ_DMA_READ_END);352353card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);354card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2);355card->recv.dmaend = card->recv.dmastart +356(4 * (NJ_DMA_RXSIZE - 1));357card->recv.dmairq = card->recv.dmastart +358(4 * ((NJ_DMA_RXSIZE / 2) - 1));359card->recv.size = NJ_DMA_RXSIZE;360361if (debug & DEBUG_HW)362pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p"363" size %zu u32\n", card->name,364card->recv.dmastart, card->recv.dmairq,365card->recv.dmaend, card->recv.start, card->recv.size);366367outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);368outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);369outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);370return 0;371}372373static void374read_dma(struct tiger_ch *bc, u32 idx, int cnt)375{376struct tiger_hw *card = bc->bch.hw;377int i, stat;378u32 val;379u8 *p, *pn;380381if (bc->lastrx == idx) {382bc->rxstate |= RX_OVERRUN;383pr_info("%s: B%1d overrun at idx %d\n", card->name,384bc->bch.nr, idx);385}386bc->lastrx = idx;387if (!bc->bch.rx_skb) {388bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);389if (!bc->bch.rx_skb) {390pr_info("%s: B%1d receive out of memory\n",391card->name, bc->bch.nr);392return;393}394}395396if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {397if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {398pr_debug("%s: B%1d overrun %d\n", card->name,399bc->bch.nr, bc->bch.rx_skb->len + cnt);400skb_trim(bc->bch.rx_skb, 0);401return;402}403p = skb_put(bc->bch.rx_skb, cnt);404} else405p = bc->hrbuf;406407for (i = 0; i < cnt; i++) {408val = card->recv.start[idx++];409if (bc->bch.nr & 2)410val >>= 8;411if (idx >= card->recv.size)412idx = 0;413p[i] = val & 0xff;414}415pn = bc->hrbuf;416next_frame:417if (test_bit(FLG_HDLC, &bc->bch.Flags)) {418stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,419bc->bch.rx_skb->data, bc->bch.maxlen);420if (stat > 0) /* valid frame received */421p = skb_put(bc->bch.rx_skb, stat);422else if (stat == -HDLC_CRC_ERROR)423pr_info("%s: B%1d receive frame CRC error\n",424card->name, bc->bch.nr);425else if (stat == -HDLC_FRAMING_ERROR)426pr_info("%s: B%1d receive framing error\n",427card->name, bc->bch.nr);428else if (stat == -HDLC_LENGTH_ERROR)429pr_info("%s: B%1d receive frame too long (> %d)\n",430card->name, bc->bch.nr, bc->bch.maxlen);431} else432stat = cnt;433434if (stat > 0) {435if (debug & DEBUG_HW_BFIFO) {436snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",437bc->bch.nr, card->name, stat);438print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,439p, stat);440}441recv_Bchannel(&bc->bch, 0);442}443if (test_bit(FLG_HDLC, &bc->bch.Flags)) {444pn += i;445cnt -= i;446if (!bc->bch.rx_skb) {447bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,448GFP_ATOMIC);449if (!bc->bch.rx_skb) {450pr_info("%s: B%1d receive out of memory\n",451card->name, bc->bch.nr);452return;453}454}455if (cnt > 0)456goto next_frame;457}458}459460static void461recv_tiger(struct tiger_hw *card, u8 irq_stat)462{463u32 idx;464int cnt = card->recv.size / 2;465466/* Note receive is via the WRITE DMA channel */467card->last_is0 &= ~NJ_IRQM0_WR_MASK;468card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);469470if (irq_stat & NJ_IRQM0_WR_END)471idx = cnt - 1;472else473idx = card->recv.size - 1;474475if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))476read_dma(&card->bc[0], idx, cnt);477if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))478read_dma(&card->bc[1], idx, cnt);479}480481/* sync with current DMA address at start or after exception */482static void483resync(struct tiger_ch *bc, struct tiger_hw *card)484{485card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);486card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;487if (bc->free > card->send.size / 2)488bc->free = card->send.size / 2;489/* currently we simple sync to the next complete free area490* this hast the advantage that we have always maximum time to491* handle TX irq492*/493if (card->send.idx < ((card->send.size / 2) - 1))494bc->idx = (card->recv.size / 2) - 1;495else496bc->idx = card->recv.size - 1;497bc->txstate = TX_RUN;498pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,499__func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);500}501502static int bc_next_frame(struct tiger_ch *);503504static void505fill_hdlc_flag(struct tiger_ch *bc)506{507struct tiger_hw *card = bc->bch.hw;508int count, i;509u32 m, v;510u8 *p;511512if (bc->free == 0)513return;514pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,515__func__, bc->bch.nr, bc->free, bc->txstate,516bc->idx, card->send.idx);517if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))518resync(bc, card);519count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,520bc->hsbuf, bc->free);521pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,522bc->bch.nr, count);523bc->free -= count;524p = bc->hsbuf;525m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;526for (i = 0; i < count; i++) {527if (bc->idx >= card->send.size)528bc->idx = 0;529v = card->send.start[bc->idx];530v &= m;531v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;532card->send.start[bc->idx++] = v;533}534if (debug & DEBUG_HW_BFIFO) {535snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",536bc->bch.nr, card->name, count);537print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);538}539}540541static void542fill_dma(struct tiger_ch *bc)543{544struct tiger_hw *card = bc->bch.hw;545int count, i;546u32 m, v;547u8 *p;548549if (bc->free == 0)550return;551count = bc->bch.tx_skb->len - bc->bch.tx_idx;552if (count <= 0)553return;554pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,555__func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,556bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);557if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))558resync(bc, card);559p = bc->bch.tx_skb->data + bc->bch.tx_idx;560if (test_bit(FLG_HDLC, &bc->bch.Flags)) {561count = isdnhdlc_encode(&bc->hsend, p, count, &i,562bc->hsbuf, bc->free);563pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,564bc->bch.nr, i, count);565bc->bch.tx_idx += i;566bc->free -= count;567p = bc->hsbuf;568} else {569if (count > bc->free)570count = bc->free;571bc->bch.tx_idx += count;572bc->free -= count;573}574m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;575for (i = 0; i < count; i++) {576if (bc->idx >= card->send.size)577bc->idx = 0;578v = card->send.start[bc->idx];579v &= m;580v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;581card->send.start[bc->idx++] = v;582}583if (debug & DEBUG_HW_BFIFO) {584snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",585bc->bch.nr, card->name, count);586print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);587}588if (bc->free)589bc_next_frame(bc);590}591592593static int594bc_next_frame(struct tiger_ch *bc)595{596if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)597fill_dma(bc);598else {599if (bc->bch.tx_skb) {600/* send confirm, on trans, free on hdlc. */601if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))602confirm_Bsend(&bc->bch);603dev_kfree_skb(bc->bch.tx_skb);604}605if (get_next_bframe(&bc->bch))606fill_dma(bc);607else608return 0;609}610return 1;611}612613static void614send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)615{616int ret;617618bc->free += card->send.size / 2;619if (bc->free >= card->send.size) {620if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {621pr_info("%s: B%1d TX underrun state %x\n", card->name,622bc->bch.nr, bc->txstate);623bc->txstate |= TX_UNDERRUN;624}625bc->free = card->send.size;626}627ret = bc_next_frame(bc);628if (!ret) {629if (test_bit(FLG_HDLC, &bc->bch.Flags)) {630fill_hdlc_flag(bc);631return;632}633pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,634bc->bch.nr, bc->free, bc->idx, card->send.idx);635if (!(bc->txstate & (TX_IDLE | TX_INIT))) {636fill_mem(bc, bc->idx, bc->free, 0xff);637if (bc->free == card->send.size)638bc->txstate |= TX_IDLE;639}640}641}642643static void644send_tiger(struct tiger_hw *card, u8 irq_stat)645{646int i;647648/* Note send is via the READ DMA channel */649if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {650pr_info("%s: tiger warn write double dma %x/%x\n",651card->name, irq_stat, card->last_is0);652return;653} else {654card->last_is0 &= ~NJ_IRQM0_RD_MASK;655card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);656}657for (i = 0; i < 2; i++) {658if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))659send_tiger_bc(card, &card->bc[i]);660}661}662663static irqreturn_t664nj_irq(int intno, void *dev_id)665{666struct tiger_hw *card = dev_id;667u8 val, s1val, s0val;668669spin_lock(&card->lock);670s0val = inb(card->base | NJ_IRQSTAT0);671s1val = inb(card->base | NJ_IRQSTAT1);672if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {673/* shared IRQ */674spin_unlock(&card->lock);675return IRQ_NONE;676}677pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);678card->irqcnt++;679if (!(s1val & NJ_ISACIRQ)) {680val = ReadISAC_nj(card, ISAC_ISTA);681if (val)682mISDNisac_irq(&card->isac, val);683}684685if (s0val)686/* write to clear */687outb(s0val, card->base | NJ_IRQSTAT0);688else689goto end;690s1val = s0val;691/* set bits in sval to indicate which page is free */692card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);693card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;694if (card->recv.dmacur < card->recv.dmairq)695s0val = 0x08; /* the 2nd write area is free */696else697s0val = 0x04; /* the 1st write area is free */698699card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);700card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;701if (card->send.dmacur < card->send.dmairq)702s0val |= 0x02; /* the 2nd read area is free */703else704s0val |= 0x01; /* the 1st read area is free */705706pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,707s1val, s0val, card->last_is0,708card->recv.idx, card->send.idx);709/* test if we have a DMA interrupt */710if (s0val != card->last_is0) {711if ((s0val & NJ_IRQM0_RD_MASK) !=712(card->last_is0 & NJ_IRQM0_RD_MASK))713/* got a write dma int */714send_tiger(card, s0val);715if ((s0val & NJ_IRQM0_WR_MASK) !=716(card->last_is0 & NJ_IRQM0_WR_MASK))717/* got a read dma int */718recv_tiger(card, s0val);719}720end:721spin_unlock(&card->lock);722return IRQ_HANDLED;723}724725static int726nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)727{728int ret = -EINVAL;729struct bchannel *bch = container_of(ch, struct bchannel, ch);730struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);731struct tiger_hw *card = bch->hw;732struct mISDNhead *hh = mISDN_HEAD_P(skb);733u32 id;734u_long flags;735736switch (hh->prim) {737case PH_DATA_REQ:738spin_lock_irqsave(&card->lock, flags);739ret = bchannel_senddata(bch, skb);740if (ret > 0) { /* direct TX */741id = hh->id; /* skb can be freed */742fill_dma(bc);743ret = 0;744spin_unlock_irqrestore(&card->lock, flags);745if (!test_bit(FLG_TRANSPARENT, &bch->Flags))746queue_ch_frame(ch, PH_DATA_CNF, id, NULL);747} else748spin_unlock_irqrestore(&card->lock, flags);749return ret;750case PH_ACTIVATE_REQ:751spin_lock_irqsave(&card->lock, flags);752if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))753ret = mode_tiger(bc, ch->protocol);754else755ret = 0;756spin_unlock_irqrestore(&card->lock, flags);757if (!ret)758_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,759NULL, GFP_KERNEL);760break;761case PH_DEACTIVATE_REQ:762spin_lock_irqsave(&card->lock, flags);763mISDN_clear_bchannel(bch);764mode_tiger(bc, ISDN_P_NONE);765spin_unlock_irqrestore(&card->lock, flags);766_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,767NULL, GFP_KERNEL);768ret = 0;769break;770}771if (!ret)772dev_kfree_skb(skb);773return ret;774}775776static int777channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)778{779int ret = 0;780struct tiger_hw *card = bc->bch.hw;781782switch (cq->op) {783case MISDN_CTRL_GETOP:784cq->op = 0;785break;786/* Nothing implemented yet */787case MISDN_CTRL_FILL_EMPTY:788default:789pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);790ret = -EINVAL;791break;792}793return ret;794}795796static int797nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)798{799struct bchannel *bch = container_of(ch, struct bchannel, ch);800struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);801struct tiger_hw *card = bch->hw;802int ret = -EINVAL;803u_long flags;804805pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);806switch (cmd) {807case CLOSE_CHANNEL:808test_and_clear_bit(FLG_OPEN, &bch->Flags);809if (test_bit(FLG_ACTIVE, &bch->Flags)) {810spin_lock_irqsave(&card->lock, flags);811mISDN_freebchannel(bch);812test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);813test_and_clear_bit(FLG_ACTIVE, &bch->Flags);814mode_tiger(bc, ISDN_P_NONE);815spin_unlock_irqrestore(&card->lock, flags);816}817ch->protocol = ISDN_P_NONE;818ch->peer = NULL;819module_put(THIS_MODULE);820ret = 0;821break;822case CONTROL_CHANNEL:823ret = channel_bctrl(bc, arg);824break;825default:826pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);827}828return ret;829}830831static int832channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)833{834int ret = 0;835836switch (cq->op) {837case MISDN_CTRL_GETOP:838cq->op = MISDN_CTRL_LOOP;839break;840case MISDN_CTRL_LOOP:841/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */842if (cq->channel < 0 || cq->channel > 3) {843ret = -EINVAL;844break;845}846ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);847break;848default:849pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);850ret = -EINVAL;851break;852}853return ret;854}855856static int857open_bchannel(struct tiger_hw *card, struct channel_req *rq)858{859struct bchannel *bch;860861if (rq->adr.channel > 2)862return -EINVAL;863if (rq->protocol == ISDN_P_NONE)864return -EINVAL;865bch = &card->bc[rq->adr.channel - 1].bch;866if (test_and_set_bit(FLG_OPEN, &bch->Flags))867return -EBUSY; /* b-channel can be only open once */868test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);869bch->ch.protocol = rq->protocol;870rq->ch = &bch->ch;871return 0;872}873874/*875* device control function876*/877static int878nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)879{880struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);881struct dchannel *dch = container_of(dev, struct dchannel, dev);882struct tiger_hw *card = dch->hw;883struct channel_req *rq;884int err = 0;885886pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);887switch (cmd) {888case OPEN_CHANNEL:889rq = arg;890if (rq->protocol == ISDN_P_TE_S0)891err = card->isac.open(&card->isac, rq);892else893err = open_bchannel(card, rq);894if (err)895break;896if (!try_module_get(THIS_MODULE))897pr_info("%s: cannot get module\n", card->name);898break;899case CLOSE_CHANNEL:900pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,901__builtin_return_address(0));902module_put(THIS_MODULE);903break;904case CONTROL_CHANNEL:905err = channel_ctrl(card, arg);906break;907default:908pr_debug("%s: %s unknown command %x\n",909card->name, __func__, cmd);910return -EINVAL;911}912return err;913}914915static int916nj_init_card(struct tiger_hw *card)917{918u_long flags;919int ret;920921spin_lock_irqsave(&card->lock, flags);922nj_disable_hwirq(card);923spin_unlock_irqrestore(&card->lock, flags);924925card->irq = card->pdev->irq;926if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {927pr_info("%s: couldn't get interrupt %d\n",928card->name, card->irq);929card->irq = -1;930return -EIO;931}932933spin_lock_irqsave(&card->lock, flags);934nj_reset(card);935ret = card->isac.init(&card->isac);936if (ret)937goto error;938ret = inittiger(card);939if (ret)940goto error;941mode_tiger(&card->bc[0], ISDN_P_NONE);942mode_tiger(&card->bc[1], ISDN_P_NONE);943error:944spin_unlock_irqrestore(&card->lock, flags);945return ret;946}947948949static void950nj_release(struct tiger_hw *card)951{952u_long flags;953int i;954955if (card->base_s) {956spin_lock_irqsave(&card->lock, flags);957nj_disable_hwirq(card);958mode_tiger(&card->bc[0], ISDN_P_NONE);959mode_tiger(&card->bc[1], ISDN_P_NONE);960card->isac.release(&card->isac);961spin_unlock_irqrestore(&card->lock, flags);962release_region(card->base, card->base_s);963card->base_s = 0;964}965if (card->irq > 0)966free_irq(card->irq, card);967if (card->isac.dch.dev.dev.class)968mISDN_unregister_device(&card->isac.dch.dev);969970for (i = 0; i < 2; i++) {971mISDN_freebchannel(&card->bc[i].bch);972kfree(card->bc[i].hsbuf);973kfree(card->bc[i].hrbuf);974}975if (card->dma_p)976pci_free_consistent(card->pdev, NJ_DMA_SIZE,977card->dma_p, card->dma);978write_lock_irqsave(&card_lock, flags);979list_del(&card->list);980write_unlock_irqrestore(&card_lock, flags);981pci_clear_master(card->pdev);982pci_disable_device(card->pdev);983pci_set_drvdata(card->pdev, NULL);984kfree(card);985}986987988static int989nj_setup(struct tiger_hw *card)990{991card->base = pci_resource_start(card->pdev, 0);992card->base_s = pci_resource_len(card->pdev, 0);993if (!request_region(card->base, card->base_s, card->name)) {994pr_info("%s: NETjet config port %#x-%#x already in use\n",995card->name, card->base,996(u32)(card->base + card->base_s - 1));997card->base_s = 0;998return -EIO;999}1000ASSIGN_FUNC(nj, ISAC, card->isac);1001return 0;1002}100310041005static int __devinit1006setup_instance(struct tiger_hw *card)1007{1008int i, err;1009u_long flags;10101011snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);1012write_lock_irqsave(&card_lock, flags);1013list_add_tail(&card->list, &Cards);1014write_unlock_irqrestore(&card_lock, flags);10151016_set_debug(card);1017card->isac.name = card->name;1018spin_lock_init(&card->lock);1019card->isac.hwlock = &card->lock;1020mISDNisac_init(&card->isac, card);10211022card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |1023(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));1024card->isac.dch.dev.D.ctrl = nj_dctrl;1025for (i = 0; i < 2; i++) {1026card->bc[i].bch.nr = i + 1;1027set_channelmap(i + 1, card->isac.dch.dev.channelmap);1028mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);1029card->bc[i].bch.hw = card;1030card->bc[i].bch.ch.send = nj_l2l1B;1031card->bc[i].bch.ch.ctrl = nj_bctrl;1032card->bc[i].bch.ch.nr = i + 1;1033list_add(&card->bc[i].bch.ch.list,1034&card->isac.dch.dev.bchannels);1035card->bc[i].bch.hw = card;1036}1037err = nj_setup(card);1038if (err)1039goto error;1040err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,1041card->name);1042if (err)1043goto error;1044err = nj_init_card(card);1045if (!err) {1046nj_cnt++;1047pr_notice("Netjet %d cards installed\n", nj_cnt);1048return 0;1049}1050error:1051nj_release(card);1052return err;1053}10541055static int __devinit1056nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)1057{1058int err = -ENOMEM;1059int cfg;1060struct tiger_hw *card;10611062if (pdev->subsystem_vendor == 0x8086 &&1063pdev->subsystem_device == 0x0003) {1064pr_notice("Netjet: Digium X100P/X101P not handled\n");1065return -ENODEV;1066}10671068if (pdev->subsystem_vendor == 0x55 &&1069pdev->subsystem_device == 0x02) {1070pr_notice("Netjet: Enter!Now not handled yet\n");1071return -ENODEV;1072}10731074if (pdev->subsystem_vendor == 0xb100 &&1075pdev->subsystem_device == 0x0003 ) {1076pr_notice("Netjet: Digium TDM400P not handled yet\n");1077return -ENODEV;1078}10791080card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);1081if (!card) {1082pr_info("No kmem for Netjet\n");1083return err;1084}10851086card->pdev = pdev;10871088err = pci_enable_device(pdev);1089if (err) {1090kfree(card);1091return err;1092}10931094printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",1095pci_name(pdev));10961097pci_set_master(pdev);10981099/* the TJ300 and TJ320 must be detected, the IRQ handling is different1100* unfortunately the chips use the same device ID, but the TJ320 has1101* the bit20 in status PCI cfg register set1102*/1103pci_read_config_dword(pdev, 0x04, &cfg);1104if (cfg & 0x00100000)1105card->typ = NETJET_S_TJ320;1106else1107card->typ = NETJET_S_TJ300;11081109card->base = pci_resource_start(pdev, 0);1110card->irq = pdev->irq;1111pci_set_drvdata(pdev, card);1112err = setup_instance(card);1113if (err)1114pci_set_drvdata(pdev, NULL);11151116return err;1117}111811191120static void __devexit nj_remove(struct pci_dev *pdev)1121{1122struct tiger_hw *card = pci_get_drvdata(pdev);11231124if (card)1125nj_release(card);1126else1127pr_info("%s drvdata already removed\n", __func__);1128}11291130/* We cannot select cards with PCI_SUB... IDs, since here are cards with1131* SUB IDs set to PCI_ANY_ID, so we need to match all and reject1132* known other cards which not work with this driver - see probe function */1133static struct pci_device_id nj_pci_ids[] __devinitdata = {1134{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,1135PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},1136{ }1137};1138MODULE_DEVICE_TABLE(pci, nj_pci_ids);11391140static struct pci_driver nj_driver = {1141.name = "netjet",1142.probe = nj_probe,1143.remove = __devexit_p(nj_remove),1144.id_table = nj_pci_ids,1145};11461147static int __init nj_init(void)1148{1149int err;11501151pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);1152err = pci_register_driver(&nj_driver);1153return err;1154}11551156static void __exit nj_cleanup(void)1157{1158pci_unregister_driver(&nj_driver);1159}11601161module_init(nj_init);1162module_exit(nj_cleanup);116311641165