linux/drivers/isdn/hisax/jade_irq.c
<<
>>
Prefs
   1/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
   2 *
   3 * Low level JADE IRQ stuff (derived from original hscx_irq.c)
   4 *
   5 * Author       Roland Klabunde
   6 * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.de>
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12
  13static inline void
  14waitforCEC(struct IsdnCardState *cs, int jade, int reg)
  15{
  16        int to = 50;
  17        int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
  18        while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
  19                udelay(1);
  20                to--;
  21        }
  22        if (!to)
  23                printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
  24}
  25
  26
  27static inline void
  28waitforXFW(struct IsdnCardState *cs, int jade)
  29{
  30        /* Does not work on older jade versions, don't care */
  31}
  32
  33static inline void
  34WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
  35{
  36        waitforCEC(cs, jade, reg);
  37        WRITEJADE(cs, jade, reg, data);
  38}
  39
  40
  41
  42static void
  43jade_empty_fifo(struct BCState *bcs, int count)
  44{
  45        u_char *ptr;
  46        struct IsdnCardState *cs = bcs->cs;
  47
  48        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  49                debugl1(cs, "jade_empty_fifo");
  50
  51        if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
  52                if (cs->debug & L1_DEB_WARN)
  53                        debugl1(cs, "jade_empty_fifo: incoming packet too large");
  54                WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
  55                bcs->hw.hscx.rcvidx = 0;
  56                return;
  57        }
  58        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
  59        bcs->hw.hscx.rcvidx += count;
  60        READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
  61        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
  62        if (cs->debug & L1_DEB_HSCX_FIFO) {
  63                char *t = bcs->blog;
  64
  65                t += sprintf(t, "jade_empty_fifo %c cnt %d",
  66                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
  67                QuickHex(t, ptr, count);
  68                debugl1(cs, "%s", bcs->blog);
  69        }
  70}
  71
  72static void
  73jade_fill_fifo(struct BCState *bcs)
  74{
  75        struct IsdnCardState *cs = bcs->cs;
  76        int more, count;
  77        int fifo_size = 32;
  78        u_char *ptr;
  79
  80        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  81                debugl1(cs, "jade_fill_fifo");
  82
  83        if (!bcs->tx_skb)
  84                return;
  85        if (bcs->tx_skb->len <= 0)
  86                return;
  87
  88        more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
  89        if (bcs->tx_skb->len > fifo_size) {
  90                more = !0;
  91                count = fifo_size;
  92        } else
  93                count = bcs->tx_skb->len;
  94
  95        waitforXFW(cs, bcs->hw.hscx.hscx);
  96        ptr = bcs->tx_skb->data;
  97        skb_pull(bcs->tx_skb, count);
  98        bcs->tx_cnt -= count;
  99        bcs->hw.hscx.count += count;
 100        WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
 101        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME));
 102        if (cs->debug & L1_DEB_HSCX_FIFO) {
 103                char *t = bcs->blog;
 104
 105                t += sprintf(t, "jade_fill_fifo %c cnt %d",
 106                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
 107                QuickHex(t, ptr, count);
 108                debugl1(cs, "%s", bcs->blog);
 109        }
 110}
 111
 112
 113static void
 114jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
 115{
 116        u_char r;
 117        struct BCState *bcs = cs->bcs + jade;
 118        struct sk_buff *skb;
 119        int fifo_size = 32;
 120        int count;
 121        int i_jade = (int) jade; /* To satisfy the compiler */
 122
 123        if (!test_bit(BC_FLG_INIT, &bcs->Flag))
 124                return;
 125
 126        if (val & 0x80) {       /* RME */
 127                r = READJADE(cs, i_jade, jade_HDLC_RSTA);
 128                if ((r & 0xf0) != 0xa0) {
 129                        if (!(r & 0x80))
 130                                if (cs->debug & L1_DEB_WARN)
 131                                        debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A"));
 132                        if ((r & 0x40) && bcs->mode)
 133                                if (cs->debug & L1_DEB_WARN)
 134                                        debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode);
 135                        if (!(r & 0x20))
 136                                if (cs->debug & L1_DEB_WARN)
 137                                        debugl1(cs, "JADE %c CRC error", 'A' + jade);
 138                        WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
 139                } else {
 140                        count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
 141                        if (count == 0)
 142                                count = fifo_size;
 143                        jade_empty_fifo(bcs, count);
 144                        if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
 145                                if (cs->debug & L1_DEB_HSCX_FIFO)
 146                                        debugl1(cs, "HX Frame %d", count);
 147                                if (!(skb = dev_alloc_skb(count)))
 148                                        printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A"));
 149                                else {
 150                                        skb_put_data(skb, bcs->hw.hscx.rcvbuf,
 151                                                     count);
 152                                        skb_queue_tail(&bcs->rqueue, skb);
 153                                }
 154                        }
 155                }
 156                bcs->hw.hscx.rcvidx = 0;
 157                schedule_event(bcs, B_RCVBUFREADY);
 158        }
 159        if (val & 0x40) {       /* RPF */
 160                jade_empty_fifo(bcs, fifo_size);
 161                if (bcs->mode == L1_MODE_TRANS) {
 162                        /* receive audio data */
 163                        if (!(skb = dev_alloc_skb(fifo_size)))
 164                                printk(KERN_WARNING "HiSax: receive out of memory\n");
 165                        else {
 166                                skb_put_data(skb, bcs->hw.hscx.rcvbuf,
 167                                             fifo_size);
 168                                skb_queue_tail(&bcs->rqueue, skb);
 169                        }
 170                        bcs->hw.hscx.rcvidx = 0;
 171                        schedule_event(bcs, B_RCVBUFREADY);
 172                }
 173        }
 174        if (val & 0x10) {       /* XPR */
 175                if (bcs->tx_skb) {
 176                        if (bcs->tx_skb->len) {
 177                                jade_fill_fifo(bcs);
 178                                return;
 179                        } else {
 180                                if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
 181                                    (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
 182                                        u_long  flags;
 183                                        spin_lock_irqsave(&bcs->aclock, flags);
 184                                        bcs->ackcnt += bcs->hw.hscx.count;
 185                                        spin_unlock_irqrestore(&bcs->aclock, flags);
 186                                        schedule_event(bcs, B_ACKPENDING);
 187                                }
 188                                dev_kfree_skb_irq(bcs->tx_skb);
 189                                bcs->hw.hscx.count = 0;
 190                                bcs->tx_skb = NULL;
 191                        }
 192                }
 193                if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
 194                        bcs->hw.hscx.count = 0;
 195                        test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
 196                        jade_fill_fifo(bcs);
 197                } else {
 198                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 199                        schedule_event(bcs, B_XMTBUFREADY);
 200                }
 201        }
 202}
 203
 204static inline void
 205jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
 206{
 207        struct BCState *bcs;
 208        bcs = cs->bcs + jade;
 209
 210        if (val & jadeISR_RFO) {
 211                /* handled with RDO */
 212                val &= ~jadeISR_RFO;
 213        }
 214        if (val & jadeISR_XDU) {
 215                /* relevant in HDLC mode only */
 216                /* don't reset XPR here */
 217                if (bcs->mode == 1)
 218                        jade_fill_fifo(bcs);
 219                else {
 220                        /* Here we lost an TX interrupt, so
 221                         * restart transmitting the whole frame.
 222                         */
 223                        if (bcs->tx_skb) {
 224                                skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 225                                bcs->tx_cnt += bcs->hw.hscx.count;
 226                                bcs->hw.hscx.count = 0;
 227                        }
 228                        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
 229                        if (cs->debug & L1_DEB_WARN)
 230                                debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val);
 231                }
 232        }
 233        if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) {
 234                if (cs->debug & L1_DEB_HSCX)
 235                        debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val);
 236                jade_interrupt(cs, val, jade);
 237        }
 238}
 239